6

我在 MIPS 程序集中有这个程序,它来自一个 C 代码,它对函数的第 8 个参数进行简单平均。

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添加$2when $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;
}

注意:在这种情况下,由于我们使用整数而不是浮点数或双精度数,除法中可能的损失并不重要。

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 回答