【问题标题】:Bits representation of negative numbers负数的位表示
【发布时间】:2009-07-24 04:03:04
【问题描述】:

这是一个关于有符号整数位表示的疑问。例如,当要表示-1时,就相当于(+1)的2的补码。所以 -1 表示为 0xFFFFFFF。现在,当我将数字移动 31 并打印结果时,它会返回为 -1。

signed int a = -1;
printf(("The number is %d ",(a>>31));//this prints as -1

那么谁能给我解释一下这些位是如何表示负数的?

谢谢。

【问题讨论】:

  • 从另一个角度看:将任何 N 位(符号扩展)右移视为除以 2^N,向下舍入(朝向负无穷大,而不是朝向 0。)因此 -1右移(带符号扩展)任意次数将继续产生 -1。

标签: c bit-manipulation


【解决方案1】:

当最高位为零时,数字为正数。为 1 时为负数。

右移的负数不断将“1”移入最高位以保持负数。这就是你得到这个答案的原因。

有关二进制补码的更多信息,请参阅this Stackoverflow question


@Stobor 指出一些 C 实现可以将 0 移到高位而不是 1。[在 Wikipedia 中验证。]在 Java 中,它是可靠的算术移位。

但是提问者给出的输出表明他的编译器正在做算术移位。

【讨论】:

  • 但是 shud 它打印为 -1,它应该打印为 1 仪式,因为最上面但是 1 表示负数。
  • @Nosredna:您还应该提到填充符号位行为是特定于实现的。
  • 既然是负数,为什么要打印正数呢?
  • @Stobor:哦!好点子。我不知道它是。你对此有很好的参考吗?是否有任何编译器移零?无论如何,从他的例子来看,我认为他的编译器在 1 秒内发生了变化。
  • @Nosredna:CPU 寄存器对有符号与无符号一无所知 - 如果您将寄存器中的位解释为无符号数,LSR 会执行“您所期望的”,ASR 会执行“如果您将这些位解释为带符号的数字,您会期望什么。
【解决方案2】:

C 标准未定义负(必须有符号)整数的右移是否将零(逻辑右移)或符号位(算术右移)移到最高有效位。由实现来选择。

因此,可移植代码确保它不对负数执行右移。它要么在移位之前将值转换为相应的无符号值(保证使用逻辑右移,将零放入空出的位),要么确保该值为正,或者它容忍输出的变化。

【讨论】:

  • 或者它可以在移位后的最高位(或位)中“或”。
  • 非常感谢所有答案。我猜我还没有清除我的 doyubt。所以它是编译器还是硬件特定的???
  • @Maddy:这取决于硬件和编译器。例如,如果一个特定的 CPU 只有逻辑右移 (LSR) 而没有算术右移 (ASR),那么该机器的编译器将使用 LSR 而不是不存在的 ASR。它还取决于编译器;即使机器同时具有 ASR 和 LSR,编译器编写者也可能出于多种原因决定将 LSR 用于有符号和无符号数量。它可能会更快;它可能与运行相同编译器的其他平台一致;可能是编写编译器的人不喜欢 ASR。
【解决方案3】:

这是一个算术移位操作,它保留符号位并移动有符号数的尾数部分。

干杯

【讨论】:

    【解决方案4】:

    基本上有两种类型的右移。无符号右移和有符号右移。无符号右移会将位右移,导致最低有效位丢失,最高有效位被替换为 0。使用有符号右移,位右移,导致最低有效位重要位被丢失,而最高有效位被保留。有符号右移将数字除以 2 的幂(对应于移位的位数),而无符号右移是逻辑移位操作。

    “>>”运算符在其操作的数据类型为无符号时执行无符号右移,而在其操作的数据类型为有符号时执行有符号右移。因此,您需要做的是在执行位操作之前将对象转换为无符号整数类型以获得所需的结果。

    【讨论】:

    • 对于有符号整数不一定是“有符号移位”(尽管这种方式很常见)——这取决于编译器和/或硬件。
    • 是的。这是正确的。我已经在运行某些 x86 变体并使用 GCC 编译的性能良好的笔记本电脑/台式机/服务器机器上编程了很长时间,以至于通常很容易忘记对于当前应用程序的合理假设与实际标准之间的区别保证。
    【解决方案5】:

    查看two's complement 描述。它应该有帮助。

    【讨论】:

      【解决方案6】:

      编辑:在编写以下代码时,问题中的代码编写为:

      unsigned int a = -1;
      printf(("The number is %d ",(a>>31));//this prints as -1
      

      如果 unsigned int 至少为 32 位宽,那么您的编译器实际上不允许生成 -1 作为其输出(需要注意的是,您应该在将 unsigned 值转换为 int 之前将其传递给printf)。

      因为 a 是一个无符号整数,给它赋值 -1 必须给它 UINT_MAX 的值(作为与 -1 模 UINT_MAX+1 一致的最小非负值)。只要 unsigned int 在您的平台上至少有 32 位,将该无符号数量右移 31 的结果将是 UINT_MAX 除以 2^31,它必须适合 int。 (如果 unsigned int 是 31 位或更短,它可以产生任何它喜欢的东西,因为移位的结果是未指定的)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-13
        • 1970-01-01
        • 1970-01-01
        • 2011-04-26
        • 2018-04-10
        • 2015-08-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多