位操作 - rotateLeft

时间:2015-02-05 19:37:30

标签: c bit-manipulation

目标是编写一种方法,通过仅使用〜,!,|,&,^,+,>>,<<来向左移动32位机器中的n个位。 (不用于循环,if语句,等等......)。我认为我所得到的应该有效。我的问题是变量move_left似乎表现不正常。这是我的代码,它被分解为几个步骤,以便我找到问题:

int rotateLeft(int x, int n) 
 {
     int move_left = (0x20 + (~n + 1)); // 32 - n
     int expr1 = x >> n; // chopping off n bits on the right
     int expr2 = ~((~0x0) << n); // n number of 1s on the right
     int expr3 = expr2 & x; // the bits that now need to be on the left
     int expr4 = expr3 << move_left; // the correct bits on the left
     int expr7 = ~0x0 << move_left; // breaking down expr5
     int expr5 = (~((~0x0) << move_left)); //
     int expr6 = expr5 & expr1; // copying the right sided body
     int result = expr6 | expr4; //adding the left side

     printf("%d\n%d\n%d\n%d\n%d\n%d\n", move_left, expr1, expr7, expr5, expr6, expr4);

     return result;
 }

使用rotateLeft(-2147483648 [0x80000000],0 [0x0])进行测试时,结果不正确。在追踪我的论点时,印刷品是:

32
-2147483648
-1
0
0
0

我不明白move_left是32(这是对的),但是~0x0&lt;&lt; move_left在某种程度上是-1,它应该是0! (当我用expr7中的0x20替换left_right时,它会正确打印0。)

我感谢任何帮助!

2 个答案:

答案 0 :(得分:1)

根据C99标准,第6.5.7(3)条,关于bitshift运算符:

  

(...)如果右操作数的值为负或大于或等于提升的左操作数的宽度,行为未定义。

正如您所经历的那样,这不是纯粹的理论关注;存在这样的平台,其中具有此范围之外的操作数的位移操作可以执行任何数量的操作,因为它更容易/更快/更高效/需要更少的空间来构建硬件。但它并没有就此结束。第6.5.7(4)节:

  

E1 << E2的结果是E1左移E2位位置;腾出的位用零填充。如果E1具有无符号类型,则结果的值为E1 x 2 E2 ,比结果类型中可表示的最大值减少一个模数。如果E1具有签名类型和非负值,并且E1 x 2 E2 在结果类型中可表示,那么这就是结果值; 否则,行为未定义。

和(5):

  

E1 >> E2的结果是E1右移E2位位置。如果E1具有无符号类型或E1具有有符号类型和非负值,则结果的值是E1 / 2 {的商的整数部分{1}} 如果E2具有签名类型和负值,则结果值是实现定义的。

通常,超出定义范围的带符号左移将表现出可预测的行为,并且在带符号的右移位上通常会有符号扩展(意味着有一些移位为负值而零移动为正值),但你可以'依赖于此。

长话短说:如果您尝试使用带有符号整数类型的位移,那么您将度过难关。使用E1表示所有内容,包括左侧的文字转移的一面(例如,使用unsigned int而不是~0u)并注意您的右侧操作数保持在合法范围内。

那你如何在没有0if的情况下做最后一点?一种方法是拆分班次:

?:

这可行,因为 unsigned int expr1 = (x >> (n & 0xf)) >> (n & 0x10); unsigned int expr2 = ~((~0u << (n & 0xf)) << (n & 0x10)); (n & 0xf) + (n & 0x10) == (n & 0x1f)。我在这里假设未签名((x >> a) >> b) == (x >> (a + b)),否则你需要演员。

我可以想到更简单的左旋转方式,但是,这是你的功课。

答案 1 :(得分:0)

对于左旋转任务,您的代码非常复杂。 我在您的代码中看到的可能是一个问题,是一种数据类型。 当带符号的int被擦拭时,严格的符号位是coppying,例如,愚蠢的代码

    int x = 0x80000000;
    x >>=3;
    printf("%X\n", x);

打印结果:

    F0000000

但是如果数据类型更改为unsigned:

    unsigned int x = 0x80000000;
    x >>=3;
    printf("%X\n", x);

结果将是:

    10000000

因此,尝试以十六进制输出以查看发生的情况,然后尝试使用无符号类型来更改按位运算逻辑。

相关问题