为什么-INT_MIN = INT_MIN在带符号的二进制补码表示中?

时间:2012-01-18 20:53:40

标签: c++ c binary signed twos-complement

我还没有找到最低签名负数没有等效签名正数的原因? 为简单起见,我的意思是3位二进制数 100是-4?但我们不能在签名格式中得到积极的4,因为我们不能。它溢出来了。 那么我们怎么知道两个补码1000是-4 1000 0000是-128等等?我们没有原始正数

7 个答案:

答案 0 :(得分:17)

考虑它的一种方法是签名的二进制补码格式通过为每个位分配2的幂,然后翻转最后2的幂的符号来工作。让我们看一下-4,例如,它表示为100.这意味着值为

-1 x 2^2 + 0 x 2^1 + 0 x 2^0

如果我们想得到这个值的正面版本,我们必须否定它才能得到

 1 x 2^2 - 0 x 2^1 - 0 x 2^0

请注意,此值等于

 1 x 2^2 + 0 x 2^1 + 0 x 2^0

换句话说,这个值的正常二进制表示是100.但是,我们在这里遇到麻烦,因为我们使用了带符号的二进制补码表示,这意味着我们已经专门保留了4位作为符号位。因此,当我们尝试将位模式100解释为带符号的三位二进制补码值时,它会与我们开始时的情况完全相同。比特的不足正在受到伤害。

更一般地,给定n位,其中第一位是二进制补码表示中的符号位,尝试计算-1000 ... 00将返回相同的值,因为存储大正值所需的位具有赋予它的特殊含义。

那为什么要这样呢?原因是如果你只有n位,你不能存储值-2 n - 1 到2 n - 1 ,因为有2个 n +这里有1个不同的数字,只有2 ^ n个不同的位模式。因此,排除最大正数使得可以在指定的位模式中保存所有不同的数字。

但为什么要降低高价值而不是低价值呢?这是为了保持与无符号整数的二进制兼容性。在无符号整数中,值0到2 n-1 - 1都使用标准的base-two表示法进行编码。因此,对于无符号和有符号整数完全一致,无符号整数的设计使它们与前2个 n - 1 无符号整数的位数相等,范围从0到2 n - 1 - 1,包括在内。在此之后,无符号值需要最高位来编码数字,但有符号值使用此值作为符号位。

希望这有帮助!

答案 1 :(得分:12)

-INT_MIN是整数溢出,在C中是未定义的行为。

仅当有符号整数溢出换行时,

-INT_MIN才能保证等于INT_MIN。可以使用gcc启用此功能,例如使用-fwrapv选项。

编译器通常利用C中的整数溢出是未定义的行为来执行某些优化。依赖于包装的有符号整数溢出是不安全的。

一个众所周知的编译器优化示例如下

#define ABS(x) ((x) > 0 ? (x) : -(x)) 

void foo(int x){  
    if (ABS(x) >= 0) {
        // some code
    }
}

今天启用了优化选项的大多数编译器(gccicc)都会根据-INT_MIN未定义的行为来优化测试。

答案 2 :(得分:3)

一个。 n位二进制数有多种可能性,因此我们不能代表正数和负数的相同范围。

B中。我们希望以1开头的每个数字都是负数,每个以0开头的数字都是非负数。 (不是相反的,因为我们希望在签名和未签名中同样表示正数和零。因此,0表示正数的一半,因此它们只有一个地方。

答案 3 :(得分:3)

two's complement的替代品具有此类属性,称为one's complement 在一个补码形式中,最低可能值也具有有效的正形式。


一个补码的工作原理是简单地反转数字本身的所有位 例如,我们知道0110 == 6和一个补码1001 == -6。使用一个补码,我们得到的正数与负数一样多。

但是位代表1111怎么样?通过观察它,我们可以看出它是零(0000 = 0; 1111 = -0)的“负面”形式,但这样的数字没有任何意义,并且有点浪费。

相反,我们使用两个补码,类似于一个补码,但在反转这些位后,我们加一个。因此,如果我们知道0110 = 6,那么一个补码是1001,而二者的补码是1001 + 1 == 1010。使用二进制补码,我们没有“负零”,因为它会导致溢出。

另一种看待它的方式是“如果设置了最高位,则数字为负”。这意味着正范围是[0 .. 2^(bits - 1)],负范围是其他一切。正数与正数相同,但因为(在此格式中)零被认为是正数,负范围会被转移到[-1 .. (neg) 2^(bits - 1)]


让我们假设我们正在处理2位补码中的3位有符号数。那给了我们下面的表格:

BITS  VALUE
000       0
001       1
010       2
011       3

100      -4
101      -3
110      -2
111      -1

你可以看到正数和负数的数量相同,只是负数不像正数那样从0开始。

答案 4 :(得分:2)

缺少的数字是0。在数学意义上,0既不是正面也不是负面。但在二元意义上,由于0没有负位,因此它被认为是正数。换句话说,如果你想要-128到128,就不会有0。

答案 5 :(得分:1)

因为必须计数0.整数范围[-4,-1](或等效-4,-3,-2和-1)包含4个数字,其余范围为[0,3] (或者,等效地,0,1,2和3)包含4个数字,总共8个,并且3个数字二进制数具有2个3(= 8)个可能组合的幂。

这样想。形式[-n,+ n]的任何整数范围必须具有奇数大小(2 * n + 1个整数)。无论你使用什么整数二进制表示,都会有不同数量的负数和正数,因为组合数总是偶数(幂为2)。

答案 6 :(得分:0)

  

那么我们怎么知道两个补码1000是-4 1000 0000是-128   等等?我们没有原始正数

你的错误是认为我们需要正数的二进制补码表示,以便计算负数的二进制补码表示。

找到负数的二进制补码的过程是:

从要表示的数字的绝对值的正常非二进制补码表示开始。因此对于-4,采用| -4 |,100的非二进制补码表示。

翻转所有位:100 - > 011(或...... 11111011,其中一些无限期地继续向左)。

添加一个:011 - > 100(或...... 11111100)

现在截断到你正在使用的位数(这消除了进位或1s的无限串)。结果,100是-4的2位补码表示。

换句话说,取两个补码表示(100)翻转位(011)并加一个(100),你现在得到| -4 |的非二进制补码表示。 1 * 2 ^ 2 + 0 * 2 ^ 1 + 0 * 2 ^ 0 = 4.因此我们知道我们从100开始的表示是-3的2位补码表示。