【问题标题】:Odd bit shifting results in C#C# 中的奇数位移结果
【发布时间】:2023-04-04 07:49:01
【问题描述】:

鉴于我的 uint 值为 2402914,并且我想获取最左边的 17 位,通过执行此代码,我的逻辑中的错误在哪里:

int testop = 0;
byte[] myArray = BitConverter.GetBytes(2402914);    
fixed (byte* p = &myArray[0])    
{   
    testop = *p >> 15;    
}

我的预期输出是

50516.

【问题讨论】:

  • 你实际获得了什么价值?
  • myArray is: [98, 170, 36, 0] *p 是指向 myArray[0] 或 (byte)98 的指针,然后您将其移动 15 个位置,直接移出的 8 位范围。我认为。我对位操作有点生疏了。
  • 只有我,还是不是 C#,而是 C 或 C++?我想我在那里看到了指针。除非我遗漏了一些明显的东西。
  • @Andy 你可以在c#中做指针,它只需要在unsafe上下文中
  • 哇,太棒了。对不起,我的无知使这篇文章变得混乱。 :) 不敢相信我错过了这个。

标签: c# .net bitwise-operators fixed bit-shift


【解决方案1】:

您可能希望让您的期望与现实相匹配。右移相当于除以 2。您实际上是除以 2 十五次,这与说您除以 2^15 = 32768 相同。请注意,2402914 / 32768 = 73(截断余数)。

因此,我希望结果是 73,而不是 50516。

其实

2402914_10 = 0000 0000 0010 0100 1010 1010 0110 0010_2

所以最左边的十七位是

             0000 0000 0010 0100 1

注意

0000 0000 0010 0100 1 = 1 * 1 + 0 * 2 + 0 * 4 + 1 * 8 + 0 * 16 + 0 * 32 + 1 * 64 
                      = 73

请注意,您可以更简单地获得此结果

int testop = 2402914 >> 15;

【讨论】:

  • 他不是在移动一个int(尽管他打算这样做),而是在移动一个字节。结果变为零。
  • @Aasmund Eldhuset:什么? “鉴于我的 uint 值为 2402914,并且我想获取最左边的 17 位,通过执行此代码,我的逻辑中的错误在哪里”和“我的预期输出是 50516。”根据他所说的问题,他的预期输出是错误的。
  • @Jason - Aasmund 符合我的意图。这只是 C++ 思维方式试图应用于 C# 世界的一个案例。
  • @Jason(提问者)如果这段代码在 C/C++ 中按您的意图工作,我会感到非常惊讶。我希望 C++ 在这里给出与 C# 相同的结果。那么这与 C++ 的思维方式有什么关系呢?
  • @Jason:这与语言问题无关。如果您取 2402914 并希望它的 17 个最高有效位作为某个整数的 17 个最低有效位,您将得到 73,而不是您期望的 50516。要获得此结果,您只需移动 15 位。你可以做到这一点是由 C 派生的任何现代语言 2402914 >> 15。
【解决方案2】:

*p 只是给你第一个字节;它相当于p[0]。您必须使用移位和 ORing 来组合前三个字节(或后三个字节,具体取决于字节序...)中的位

如果此代码不是更复杂的代码的简化版本,并且您实际上只是尝试从 int 中提取最左边的 17 位,那么应该这样做:

int testop = (someInt >> 15) & 0x1ffff;

(编辑:添加了& 0x1ffff 使其也适用于负整数;感谢@James。)

【讨论】:

  • Aasmund,这就是我最初想出的。尽管它起作用了,但我仍然想了解为什么我的换档不起作用。这是有道理的,但我希望指针指向数组的第一个条目,并在我移动时继续进入内存。哦,好吧。
  • @Jason:当您取消引用指针时,您会收到一个单字节值,对其进行的任何操作只能看到该字节,而看不到它旁边的内容。
  • @Jason:但是如果你想从int 中提取位,你不能直接将>> 应用到int 上吗?查看我的编辑。
  • 我没有对你投反对票,但你需要在右移签名整数时注意符号保存。
  • @James:好点;我编辑了代码以使其处理负数。
【解决方案3】:

哇,这是一个非常有趣的谜题。不是编程部分,而是试图弄清楚你从哪里得到数字 50516 以及你试图用你的代码做什么。看起来您正在获取 16 个最低有效位并将它们向左旋转 9 位。

2402914: 0000 0000 0010 0100 1010 1010 0110 0010
 left 9: 0100 1001 0101 0100 1100 010 
  match:                     ^^^^ ^^^  
>>50516:                     1100 0101 0101 0100
  match:                             ^ ^^^^ ^^^^
right 7:                             1 0101 0100 110 0010

int value2 = value & 0xffff;
int rotate9left = ((value2 << 9) & 0xffff) | ((value2) >> (16 - 9));

我不知道您为什么使用字节数组,但您似乎认为您的 fixed() 语句正在遍历数组,但事实并非如此。您在固定块中的语句采用myArray[0] 处的字节值并将其右移15 位(移位填充0,而不是旋转将前位环绕到后)。任何超过 8 的东西都会给你零。

【讨论】:

    【解决方案4】:

    据我了解,您可以将位移运算符直接应用于 int 数据类型,而不是经历不安全代码的麻烦。

    例如:

    2402914 >> 15 = 73
    

    这与 Jason 预测的结果有关。

    另外,我注意到

    2402914 >> 5 = 75091
    and 2402914 >> 6 = 37545
    

    这表明您需要的结果无法通过任何类似的右移来实现。

    【讨论】:

      猜你喜欢
      • 2012-07-23
      • 2023-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多