【问题标题】:Are negative numbers that are left shifted *always* filled in with "1" instead of "0"?左移的负数*总是*用“1”而不是“0”填充吗?
【发布时间】:2013-03-10 23:56:06
【问题描述】:

我正在通过将一些 C++ 函数移植到 .NET 的 BigInteger 来独立研究位移。我注意到当我移动 BigInteger 时,空白被填充了。

我相信这与以二进制补码形式存储的负数有关。

BigInteger num = -126;
compactBitsRepresentation = (uint)(int)(num << 16);

这是移位后发生的事情(最高有效位在前)

10000010 will be shifted 16
11111111100000100000000000000000 was shifted 16

我应该总是期望类似的位移操作以这种方式起作用吗?这是否与 OpenSSL 等“bigNumber”的不同语言和实现一致?

【问题讨论】:

    标签: c++ .net biginteger bit-shift twos-complement


    【解决方案1】:

    来自BigInteger.LeftShift operator docs

    与整数基元的按位左移操作不同, LeftShift 方法保留原始 BigInteger 值的符号。

    所以 .NET 可以保证您看到的行为。

    我对 bignum 库不太熟悉,但 OpenSSL 的 BIGNUM BN_lshift()` 函数的文档说:

    BN_lshift() 将 a 左移 n 位并将结果放入 r ("r=a*2^n")。 BN_lshift1() 将 a 左移一位并将结果放入 r ("r=2*a")。

    由于该操作是根据乘以 2 的幂来定义的,如果将生成的 BIGNUM 转换为二进制补码(我不知道 BIGNUM 如何在内部表示数字),那么您将看到与 .NET 类似的行为.

    如果其他 bignum 库的行为类似,我不会感到惊讶,但如果您想依赖这些行为,您确实需要查看文档。但是,由于移位与乘以或除以 2 的幂非常相似,因此您可以通过使用适当的乘法或除法而不是移位来获得“可移植”行为。那么您需要确保的就是您可以转换为二进制补码表示(这是一个真正独立于移位操作行为的问题)。

    【讨论】:

      【解决方案2】:

      我应该总是期望类似的位移操作以这种方式起作用吗?

      如果有问题的数字格式使用二进制补码来表示负数(很多都这样做),您应该这样做。为了形成一个数字的二进制补码,您将所有位反转并加一,例如:

      23 is represented as 00010111
      -23 is represented as 11101001 (that is, 11101000 + 1)
      

      此外,当您将一个类型转换为更大的类型时,该值通常是符号扩展的,即最左边的位被扩展为更大类型中的额外位。这保留了数字的符号。

      所以是的,数字表示用 1 来“填充”数值是很常见的。

      【讨论】:

        【解决方案3】:

        10000010 先改成更大的宽度。在这种情况下,4 个字节:

        10000010 --> 11111111 11111111 11111111 10000010
        

        你在左边得到 1,因为数字是负数。

        现在左移只是从右边插入 0 并从左边抛出位:

        11111111 11111111 11111111 10000010 << 16 -->
        11111111 10000010 00000000 00000000
        

        【讨论】:

        • 这是标准的 C++ 行为吗? IIRC 它是定义的实现,而不是标准行为。
        • 在 C 或 C++ 中左移一个负数实际上是未定义的行为。
        • @RichardJ.RossIII,我不知道。我并不是要使用“由标准定义”这个短语,而是“它是 C++ 的东西,与 .net 或 biginteger 无关”。不过还是删了。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多