6

このプログラムは、関数の8番目の引数の単純な平均を実行するCコードからのMIPSアセンブリに含まれています。

average8:
    addu $4,$4,$5
    addu $4,$4,$6
    addu $4,$4,$7
    lw $2,16($sp)
    #nop
    addu $4,$4,$2
    lw $2,20($sp)
    #nop
    addu $4,$4,$2
    lw $2,24($sp)
    #nop
    addu $4,$4,$2
    lw $2,28($sp)
    #nop
    addu $2,$4,$2
    bgez $2,$L2
    addu $2,$2,7
$L2:
    sra $2,$2,3
    j $31

数値が正の場合は直接8で除算します(3ビットシフト)が、数値が負の場合は最初addu 7に除算を行います。

私の質問は、なぜいつ追加する7のですか?$2$2 is not >= 0


編集:これがCコードです:

int average8(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8)
{
    return (x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8) / 8;
}

注:この場合、floatまたはdoubleの代わりにintを使用しているため、除算で損失が発生する可能性はありません。

4

2 に答える 2

10

この違いは、負の数が含まれる場合の/ 8との異なる動作を説明しているようです。>> 3

int main() {
    printf("%d\n", (-50) / 8);
    printf("%d\n", (-50) >> 3);
    printf("%d\n", (-50 + 7) >> 3);
}

与える

-6
-7
-6

そのため、コンパイラは最適化を使用したいと考えています>> 3が、それは とまったく同じではない/ 8ため、それを修正するコードを追加します。

于 2012-09-02T16:07:33.007 に答える
0

オーウェンの答えを見た後、ここに彼の答えへの追加があります。これは、バイナリレベルでの違いを説明しています:

丸めに関する問題は、バイナリ レベルで発生します。

50; // 0011 0010
50 >> 3 // 0000 0110 which is 6

-50;  // 1100 1110
-50 >> 3; // 1111 1001 -> which is -7

したがって、問題を修正するには、数値に 2E(rightShift -1) を適用して、丸めの問題を修正する必要があります。

-50 + 7; // 1101 0101
-43 >> 3; // 1111 1010 -> which is -6 (and this is what was expected)

しかし、その数がすでに 8 で割り切れる場合はどうなるでしょうか。まあ問題はないでしょう!

-32; // 1110 0000
-32 >> 3; // 1111 1100 -> which is -4 (that's already the good answer)

-32+7; // 1110 0111
-25 >> 3; // 1111 1100 -> which is still -4. 

数値を 8 で割ることができる場合、答えに 7 を追加しても 3 つの LSB は変更されないため、3 の右論理シフトは変更されないことに注意してください。

于 2013-03-17T18:02:57.337 に答える