c# - << 运算符的奇怪行为

标签 c# bit-shift

在处理 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 == 0xFFFFFFFF0xFFFFFFFF & 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/

相关文章:

c - 如果该位介于低和高之间,则将 0 位变为 1 位

java - 了解按位条件检查以获取传递的数组中所有可能的组合总和

c - 以 32/64 位数量有效地移位字节?

c - 存储在 1 字节数组中的浮点型位移

c# - Unity Container - 具有通用工作统一性的多个数据库

c# - WPF DataGrid(MultiSelector?)多次引发 SelectedItems CollectionChanged 事件

c# - 在C#中嵌入一个Lua交互提示窗口

c# - KeepAlive 与 WCF 和 TCP?

c - 按位数组错误

c# - 使用 Roslyn 修改方法体