在处理 C# 移位运算符时,我遇到了左移运算符的意外行为。
然后我尝试了这个简单的功能:
for (int i = 5; i >= -10; i--) {
int s = 0x10 << i;
Debug.WriteLine(i.ToString().PadLeft(3) + " " + s.ToString("x8"));
}
结果是:
5 00000200
4 00000100
3 00000080
2 00000040
1 00000020
0 00000010
-1 00000000 -> 00000008 expected
-2 00000000 -> 00000004 expected
-3 00000000 -> 00000002 expected
-4 00000000 -> 00000001 expected
-5 80000000
-6 40000000
-7 20000000
-8 10000000
-9 08000000
-10 04000000
直到今天,我都希望 <<
运算符可以处理第二个操作数的负值。
MSDN当使用第二个操作数的负值时,不会说明任何行为。但是 MSDN 说运算符只使用低 5 位 (0-31),这应该适合负值。
我也试过 long
值:long s = 0x10L << i;
, 但结果相同。
那么这里发生了什么?
编辑
如您的回答所述,负值表示不是造成这种情况的原因。
我在所有情况下都得到了相同的错误结果:
0x10<<-3 = 0x00000000 (wrong!)
0x10<<(int)(0xfffffffd) = 0x00000000 (wrong!)
0x10<<(0x0000001d = 0x00000000 (wrong!)
expected = 0x00000002
编辑#2
这两个之一应该是真的:
1) 移位运算符是一个真正的移位运算符,所以结果应该是:
1a) 0x10 << -3 = 00000002
1b) 0x10 << -6 = 00000000
2) 移位运算符是一个旋转运算符,所以结果应该是:
2a) 0x10 << -3 = 00000002
(与 1a 相同)
2b) 0x10 << -6 = 40000000
但显示的结果既不适合 1) 也不适合 2) !!!
最佳答案
负数是两个补码,所以 -1 == 0xFFFFFFFF
,0xFFFFFFFF & 31 == 31
,-2 == 0xFFFFFFFE
, 和 0xFFFFFFFE & 31 == 30
等等。
-10 == 0xFFFFFFF6, and 0xFFFFFFF6 & 31 == 22, in fact:
(0x10 << 22) == 04000000
一些要显示的代码:
const int num = 0x10;
int maxShift = 31;
for (int i = 5; i >= -10; i--)
{
int numShifted = num << i;
uint ui = (uint)i;
int uiWithMaxShift = (int)(ui & maxShift);
int numShifted2 = num << uiWithMaxShift;
Console.WriteLine("{0,3}: {1,8:x} {2,2} {3,8:x} {4,8:x} {5}",
i,
ui,
uiWithMaxShift,
numShifted,
numShifted2,
numShifted == numShifted2);
}
long
是一样的,但现在 & 31
变成了 & 63
。 -1 == 63
、-2 == 62
和 -10 == 54
一些示例代码:
const long num = 0x10;
int maxShift = 63;
for (int i = 5; i >= -10; i--)
{
long numShifted = num << i;
uint ui = (uint)i;
int uiWithMaxShift = (int)(ui & maxShift);
long numShifted2 = num << uiWithMaxShift;
Console.WriteLine("{0,3}: {1,8:x} {2,2} {3,16:x} {4,16:x} {5}",
i,
ui,
uiWithMaxShift,
numShifted,
numShifted2,
numShifted == numShifted2);
}
明确一点:
(int x) << y == (int x) << (int)(((uint)y) & 31)
(long x) << y == (long x) << (int)(((uint)y) & 63)
而不是
(int x) << y == (int x) << (Math.Abs(y) & 63)
(long x) << y == (long x) << (Math.Abs(y) & 63)
而你认为“应该是”“如果它是它会很漂亮”“必须是”ecc 无关紧要。虽然 1 和 0 是“近”(它们的二进制表示在不同位数上的“距离”为 1),但 0 和 -1 是“远”(它们的二进制表示在位数上的“距离”为 32 或 64不同的位)
你认为你应该得到这个:
-1 00000000 -> 00000008 expected
-2 00000000 -> 00000004 expected
-3 00000000 -> 00000002 expected
-4 00000000 -> 00000001 expected
但实际上您没有看到的是您得到了这个:
-1 (00000008) 00000000
-2 (00000004) 00000000
-3 (00000002) 00000000
-4 (00000001) 00000000
-5 (00000000) 80000000 <-- To show that "symmetry" and "order" still exist
-6 (00000000) 40000000 <-- To show that "symmetry" and "order" still exist
(...)
中的部分是 int
的“左侧”部分,该部分不存在。
关于c# - << 运算符的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18126555/