C Traps:运算
位移
如果sizeof(int) = 4,那么下面的代码的结果是什么?
int x=255; printf("%d", x>>34);
实际输出:63
在编译这个代码时,编译器会给出警告
[Warning] right shift count >= width of type [enabled by default]
(这时假设位移运算位移步数只能在[0, type_bit_width)范围内)位移操作会对其位移步数对数值位宽(这里int类型为32位)做一次求余操作即上述代码等同于
x >> (34 % 32)
实际上上述的等同不完全正确,当位移步数是负数时
x >> -1 // 0
这时通过%操作不能把位移步数转化到[0, type_bit_width)范围内(-1 % 32 = -1)
更为正确的我们可以用以下代码来等效(商向负无穷取整的一种取余方式,正数:n % m,负数:n % m + m,详见“取余”一节)
int shift = -1 int q = floor(shift / 32.0); double r = i - q * 32.0; x >> (int)(r)
可以写一段代码进行测试
#include <stdio.h> #include <math.h> int main() { for (int i=-1; i>-65; i--) { int sh = i; int q = (int)floor(sh / 32.0); double r = sh - q * 32; printf("custommod: q = % d, r = % g\n", q, r); int xn = 255; printf("%d>>%d = %d\n", xn, sh, xn>>(sh)); } return 0; }
输出见:http://codepad.org/RzYr6fkI
取余
取余围绕一下公式进行
q * b + r = a
其中q = [a / b],r为余数。
但当a / b为一个浮点数时,它向那个方向取整决定了余数r的取值
- %:朝0取整(a/b为正时向负方向取整,为负时向正方向取整)
下面给出一个比较代码(c中的%操作和上一节中自定义的取余方式)
1 for (int i=-15; i<16; i++) { 2 if (i == 0) continue; 3 printf("(%2d, %d)\n", i, 3); 4 printf("%% : q = % d, r = % d \n", i / 3, i % 3); 5 int q = floor(i / 3.0); 6 double r = i - q * 3; 7 printf("custommod: q = % d, r = % g\n", q, r); 8 }
运行结果见:http://codepad.org/jSmd5Jnq
另外c语言math库中另有一些取余函数:
- remainder:商向最接近的整数取整
- remquo:商向最接近的整数取整
- fmod:商直接截断小数部分(即向0取整),与%运算符一致
另外在python中%的行为模式与上文自定义的那个取余方式一致见代码:http://codepad.org/XFangjmO
参考:
http://www.cplusplus.com/reference/cmath/remainder/
C traps & pitfalls
http://blog.csdn.net/huasion/article/details/6855900