目标是编写一种方法,通过仅使用〜,!,|,&,^,+,>>,<<来向左移动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。)
我感谢任何帮助!
答案 0 :(得分:1)
根据C99标准,第6.5.7(3)条,关于bitshift运算符:
(...)如果右操作数的值为负或大于或等于提升的左操作数的宽度,行为未定义。
正如您所经历的那样,这不是纯粹的理论关注;存在这样的平台,其中具有此范围之外的操作数的位移操作可以执行任何数量的操作,因为它更容易/更快/更高效/需要更少的空间来构建硬件。但它并没有就此结束。第6.5.7(4)节:
E1 << E2
的结果是E1
左移E2
位位置;腾出的位用零填充。如果E1
具有无符号类型,则结果的值为E1
x 2E2
,比结果类型中可表示的最大值减少一个模数。如果E1
具有签名类型和非负值,并且E1
x 2E2
在结果类型中可表示,那么这就是结果值; 否则,行为未定义。
和(5):
E1 >> E2
的结果是E1
右移E2
位位置。如果E1
具有无符号类型或E1
具有有符号类型和非负值,则结果的值是E1
/ 2 {的商的整数部分{1}} 。 如果E2
具有签名类型和负值,则结果值是实现定义的。
通常,超出定义范围的带符号左移将表现出可预测的行为,并且在带符号的右移位上通常会有符号扩展(意味着有一些移位为负值而零移动为正值),但你可以'依赖于此。
长话短说:如果您尝试使用带有符号整数类型的位移,那么您将度过难关。使用E1
表示所有内容,包括左侧的文字转移的一面(例如,使用unsigned int
而不是~0u
)并注意您的右侧操作数保持在合法范围内。
那你如何在没有0
和if
的情况下做最后一点?一种方法是拆分班次:
?:
这可行,因为 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
因此,尝试以十六进制输出以查看发生的情况,然后尝试使用无符号类型来更改按位运算逻辑。