我在MIPS程序集中有这个程序,它来自一个C代码,它执行函数的第八个参数的简单平均值。
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;
}
注意:由于我们使用整数而不是浮点数或双精度数,因此在分区中可能造成的损失在这种情况下并不重要。
答案 0 :(得分: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
不完全相同,因此它添加了一些代码来纠正它。
答案 1 :(得分: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的右逻辑移位保持不变。