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

posted @ 2014-04-13 11:43  卖程序的小歪  阅读(222)  评论(0编辑  收藏  举报