【问题标题】:What does "-1" represent in the value range for unsigned int and signed int?“-1”在 unsigned int 和 signed int 的取值范围内代表什么?
【发布时间】:2019-08-29 05:21:21
【问题描述】:

我正在学习 C 并且有一个关于 unsigned int 和signed int 值范围内的“-1”的愚蠢问题。我似乎无法在任何地方找到解释。

下面的段落解释了数据范围。但是,它没有解释“-1”。 “-1”代表/意味着什么?是 -1 是因为它跳过了 0 而 0 没有价值吗?

在 32 位整数中,无符号整数的范围为 0 到 2^32 -1 = 0 到 4,294,967,295 或大约 40 亿。签名版本从 -2^31 -1 到 2^31,即 –2,147,483,648 到 2,147,483,647 或大约 -20 亿到 +20 亿。范围是相同的,但它在数轴上移动。

【问题讨论】:

  • 其实“签名版本从-2^31 -12^31 [...]”有错误.它必须是“签名版本从 -2^312^31 -1 [...]”,就像其他人说的那样:“即 –2,147,483,648到 2,147,483,647"。
  • @Yunnosch Non-2 的补码 32 位最小值将是 -2^31 + 1,而不是 -2^31 -1。也许原来的() 不见了,就像-(2^31 -1)
  • 它是 -1,因为 0 表示的,并且少了一个位模式可用于表示非零数字。
  • 读起来很烦人。 - 实际上是一个减号。改写range of 0 to 2^32 - 1 或者更好的是range of 0 to 2³²-1
  • 字面意思的意思是从前一个值中减去1。在表达式2^32-1 中,它的意思是“计算 2 的 32 次方,然后减去 1。”

标签: c


【解决方案1】:

考虑使用 2 位可以实现的值:

00 : 0
01 : 1
10 : 2
11 : 3

其中有 4 个,2 的 2 次方。
但最高值不是 4,而是 3。
最大值是 2 的 2 次方减去 1。即在你的代表中

2^2-1
或 22-1

加一点,你会得到两倍的数字,通过添加

100 : 4
101 : 5
110 : 6
111 : 7

总数字 8,但最高数字 7。

所以“-1”是因为总是 2n 总数中的第一个用于 0,
第 2 个用于 1,第 3 个用于 2。
最终第 (2n) 个不能用于 2n,它已经用于 2n-1。

【讨论】:

    【解决方案2】:

    n 位可以表示 2n 个不同的值。 (第一位可以有两个值 * 第二位可以有两个值 * 第三位可以有两个值 * ...)

    例如,3 位可以形成 23 = 8 个不同的位模式,因此最多可以形成 8 个不同的值。

    000
    001
    010
    011
    100
    101
    110
    111
    

    如果每个位模式代表一个整数,那么一个n位整数可以代表2n个不同的整数。例如,

    • 它可以表示从 0 到 2n-1 的整数
      (因为 (2n-1) - (0) + 1 = 2n 个不同的值)。

      例如,

      000   0
      001   1
      010   2
      011   3
      100   4
      101   5
      110   6
      111   7
      
    • 它可以表示从 -2n-1 到 2n-1-1 的整数
      (因为 (2n-1-1) - (-2n-1) + 1 = 2n 个不同的值)。

      例如,

      100  -4
      101  -3
      110  -2
      111  -1
      000   0
      001   1
      010   2
      011   3
      

    您可以为这些值指定任何含义,但前面所述的范围是二进制补码机器分别对无符号整数和有符号整数理解的范围。[1]


    1. ones'-complement 机器上,有两种写入零的方法(0000...00002 和 1000...00002),因此范围只有 -2n-1-1 到 2n-1-1。不过,我认为所有现代机器都是twos'-complement 机器。

    【讨论】:

    • 作为一个好奇心:double, float 的有效数字是符号大小。因此,熟悉这种格式会有所帮助。
    • 我在您的回答中了解了更好的指数格式。谢谢。
    • ikegami,详细信息:IEEE FP 使用 sign magnitude 类似编码,而不是 ones' 补码。另请注意' 位置。
    • 和 IEEE 浮点 is encoded 中的 exponentoffset,其中全零模式是可能的最小值,对应于零的模式是在(原始无符号二进制)范围的中间。 (除了在 IEEE FP 中,全零模式是特殊的,所以 ...00001 是最小的指数。)
    • 2^n 个不同的值。不必要。它可以保存 2^n 个不同的位模式(在 C 中:对象表示)。对于一个人的补码或符号/幅度编码,值0 有两种冗余编码。 (例如,在 IEEE 浮点中,-0.0 通常被认为与+0.0 具有相同的值,即使有关于符号位传播的有符号零的规则......)IEEE 754 浮点数甚至将它们的大部分位模式用于不代表任何的NaN编码。
    【解决方案3】:

    除了@Yunnosch 对无符号数的出色解释外,几乎所有现代计算机都使用“二进制补码”来表示有符号二进制整数。 在二进制补码中,最高有效位用作“符号位”,位是数字的绝对值 + 1 的补码。因此,对于 3 位示例,虽然无符号值的范围是 0 到 7,但范围对于有符号值是 -4 到 3:

    100 : -4
    101 : -3
    110 : -2
    111 : -1
    000 :  0
    001 :  1
    010 :  2
    011 :  3
    

    请注意,对于有符号数,负数的范围比正数的范围大一。这是因为,虽然在数论中,0 既不是正数也不是负数,但在二进制表示中,0 必须是负数或正数。因为它已清除了最高有效位,所以0 是正数域的一部分,因此少了一个可用的正数。

    【讨论】:

    • 谢谢@Yunnosch,我相应地编辑了我的帖子。自从我学习以来已经有太多年了,我应该在发布之前检查我的工作。 ;)
    • 恐怕“数的绝对值的补码 + 1”会被误读为 -1 = ~(1+1) -> ~ 2 -> 101。问题是散文中缺少“()”,因此可以这样阅读。任何已经了解这些机制的人都会正确阅读您的文本,因此没有错。但是那些需要解释的人可能会感到困惑。
    • 感谢您对我的名字的意见。散文的措辞仍然很棘手。 (如你所见,我现在已经注意到我的错字了......)
    【解决方案4】:

    对于无符号整数类型,值 -1 超出范围,不能在该类型的变量中表示。如果您尝试将 -1 分配给 unsigned int,则会根据 C 标准的规则发生转换

    有符号值到无符号整数类型的转换在C standard 的第 6.3.1.3p2 节中指定:

    否则,如果新类型是无符号的,则值为 通过重复加或减多一转换 新类型可以表示的最大值 直到值在新类型的范围内。60

    ...

    60) 规则描述的是数学值的算术运算,而不是给定类型表达式的值

    假设在您的示例中 unsigned int 的值范围为 0 到 4,294,967,295,则值 -1 通过添加 -1 + 4,294,967,296 = 4,294,967,295 进行转换。请注意,无论在给定系统上如何表示负数,都会发生这种转换。两个人的恭维、一个人的恭维或符号和大小都是一样的。

    请注意,这意味着转换后的值的表示不必与 -1 的表示相同。

    以 4 位类型为例,将值 -1 转换为无符号类型得到值 15。这些数字的表示如下:

                    sign-and magnitude    ones' complement   two's complement
      -1   (signed)               1001                1110               1111
      15 (unsigned)               1111                1111               1111
    

    虽然在二进制补码的情况下,转换的结果保持相同的表示,但在其他两种情况下会发生变化。对于一个补码,-1 的表示与 14 相同,对于符号和大小,-1 的表示与 9 相同。

    所以关于二进制补码的其他答案很可能是这些实现如何做到的(即将 -1 的表示重新解释为无符号值),但是从 C 语言作为抽象机器的角度来看,我已经描述了是执行此转换的唯一正确方法。

    【讨论】:

    • 这是对如何在 C 中将 -1 转换为无符号值的问题的全面而有启发性的报道。这就是我在阅读标题时认为的问题。在阅读了问题正文和评论线程后,我不确定 OP 是否可能意味着“2^32-1”中的“-1”。
    【解决方案5】:

    您在哪里找到了这个错误的段落?它似乎是关于 2 的补码,但 -1 的位置错误。

    对于使用补码或符号/幅度有符号整数的 C 实现,范围围绕零对称(使用 2 位模式都表示 0,因此正范围和负范围大小相同)。

    如今基本上没有人使用它,但 ISO C 标准规定有符号整数是二进制的,并且使用二进制补码、一个补码或符号/大小。


    2's complement(这些天几乎普遍)中,使用 n 位的可表示值的范围是 [- 2n-1 , 2n-1 - 1 ]。 一个位模式(所有位为零)表示值为零。每个位的位值为2^i,除了最后一位的位值为-2^(n-1)

    设置了所有位的位模式表示-1,因为sum(2^i, i=0..n-1)2^n 小一。

    设置符号位,我们得到最大负数-INT_MIN 是有符号溢出(未定义行为),因为它不能表示为 @987654331 @;它需要一个更宽的整数。或者带有包装,-INT_MIN = INT_MIN。这就是“2 的补码异常”。 https://en.wikipedia.org/wiki/Two%27s_complement#Most_negative_number

    如果你在做绝对值运算,你可以避免扩大:例如
    unsigned abs = i >= 0 ? i : -(unsigned)i;

    (在 C 中将负值转换为 unsigned 具有明确定义的模减少行为,直到它处于可表示范围内。在 C 中,这与有符号整数编码无关;重要的是 。所以(uint8_t)-1 总是 255。对于 2 的补码,它只是复制位模式。对于符号/幅度或补码,C 实现必须做一些数学运算才能从中转换签名到签名。请注意,我做了这个 before 否定,这意味着 0 - i 使用通常的未签名包装。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-02
      • 1970-01-01
      • 2021-08-07
      • 2012-07-15
      • 2010-12-24
      • 1970-01-01
      相关资源
      最近更新 更多