哪种有符号整数除法对应位移位?
Which kind of signed integer division corresponds to bit shift?
众所周知,将整数除以 2 的幂时,好的编译器会将其强度归约为位移。
例如:
int main(int argc, char **argv) {
return argc/2;
}
Clang -O2 将其编译为:
movl %ecx, %eax
shrl , %eax
addl %ecx, %eax
sarl %eax
retq
值得注意的是,虽然这个指令序列比实际的除法指令快得多,但并非人们希望的只是一个位移位。大概是因为典型的 CPU 和 C 最终选择了截断除法(商向零舍入),而这恰好与算术右移不完全匹配(并且需要强度降低以准确保留语义)。
哪种有符号整数除法会与算术右移完全匹配?
如果执行算术右移,floor
乘以2的幂是最合适的运算,它匹配有符号整数右移(向[=23=舍入) ]-inf).
请注意,有符号整数的右移是实现定义的。它可能是算术右移(由大多数知名编译器实现)或逻辑右移。有关这两种操作之间差异的更多信息,请参见 .
算术右移示例:https://godbolt.org/z/zhhfbc
#include <stdio.h>
#include <math.h>
int main(void)
{
int val1 = 7;
int val2 = -7;
printf("Value1 = %.1lf\n", floor(val1/2.0));
printf("Value2 = %.1lf\n", floor(val2/2.0));
printf("Value1 = %d\n", val1 >> 1);
printf("Value2 = %d\n", val2 >> 1);
return 0;
}
输出为:
Value1 = 3.0
Value2 = -4.0
Value1 = 3
Value2 = -4
众所周知,将整数除以 2 的幂时,好的编译器会将其强度归约为位移。
例如:
int main(int argc, char **argv) {
return argc/2;
}
Clang -O2 将其编译为:
movl %ecx, %eax
shrl , %eax
addl %ecx, %eax
sarl %eax
retq
值得注意的是,虽然这个指令序列比实际的除法指令快得多,但并非人们希望的只是一个位移位。大概是因为典型的 CPU 和 C 最终选择了截断除法(商向零舍入),而这恰好与算术右移不完全匹配(并且需要强度降低以准确保留语义)。
哪种有符号整数除法会与算术右移完全匹配?
如果执行算术右移,floor
乘以2的幂是最合适的运算,它匹配有符号整数右移(向[=23=舍入) ]-inf).
请注意,有符号整数的右移是实现定义的。它可能是算术右移(由大多数知名编译器实现)或逻辑右移。有关这两种操作之间差异的更多信息,请参见
算术右移示例:https://godbolt.org/z/zhhfbc
#include <stdio.h>
#include <math.h>
int main(void)
{
int val1 = 7;
int val2 = -7;
printf("Value1 = %.1lf\n", floor(val1/2.0));
printf("Value2 = %.1lf\n", floor(val2/2.0));
printf("Value1 = %d\n", val1 >> 1);
printf("Value2 = %d\n", val2 >> 1);
return 0;
}
输出为:
Value1 = 3.0
Value2 = -4.0
Value1 = 3
Value2 = -4