为什么在签名的二进制补码表示中-INT_MIN = INT_MIN?
我还没有找到最低签名负数没有等效签名正数的原因? 我的意思是在3位二进制数字中为简单起见100是-4? 但是我们不能以签名格式获得积极的4,因为我们不能。 它溢出了。 那么我们怎么知道两个补码1000是-4 1000 0000是-128等等? 我们没有原始正数
考虑它的一种方法是签名的二进制补码格式通过为每个位分配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都使用标准的基数2表示法进行编码。 因此,对于无符号和有符号整数完全一致,无符号整数的设计使得它们与前2 n – 1个无符号整数一位一位,其范围为0到2 n – 1 – 1,包括0和2 n – 1 – 1 。 在此之后,无符号值需要最高位来编码数字,但有符号值使用此作为符号位。
希望这可以帮助!
-INT_MIN
是整数溢出,在C中是未定义的行为。
只有当有符号整数溢出换INT_MIN
, INT_MIN
才能保证等于INT_MIN
。 这可以使用gcc
启用,例如使用-fwrapv
选项。
编译器通常利用C中的整数溢出是未定义的行为来执行某些优化。 依赖有问题的整数溢出来换行是不安全的。
编译器优化的一个众所周知的例子如下
#define ABS(x) ((x) > 0 ? (x) : -(x)) void foo(int x){ if (ABS(x) >= 0) { // some code } }
今天的大多数编译器( gcc
, icc
)启用了优化选项,将依赖于-INT_MIN
未定义行为的事实来优化测试。
A. n位二进制数有多种可能性,因此我们不能为正数和负数表示相同的范围。
B.我们希望以1开头的每个数字都是负数,每个从0开始的数字都是否定的。 (不是相反的,因为我们希望在签名和未签名中同样表示正数和零。因此,0表示正数的一半,因此它们有一个较少的位置。
两个补码的替代品具有这样的属性,它被称为一个补码 。
在一个补码forms中,最低可能值也具有有效的正forms。
一个补码的工作原理是简单地反转数字本身的所有位。
例如,我们知道0110 == 6
并且在一个补码中1001 == -6
。 使用一个补码,我们得到的正数与负数一样多。
但是比特表示1111
怎么样? 仅仅通过观察它,我们可以看出它是零的“负”forms( 0000 = 0; 1111 = -0
),但是这样的数字没有任何意义并且有点浪费。
相反,我们使用二进制补码,类似于一个补码,但在反转位之后,我们加一个。 因此,如果我们知道0110 = 6
,那么一个补码是1001
,二补码是1001 + 1 == 1010
。 使用二进制补码,我们没有“负零”,因为它会导致溢出。
另一种看待它的方式是“如果设置了最高位,则数字为负”。 这意味着正范围是[0 .. 2^(bits - 1)]
,负范围是其他所有。 正数与正数相同,但因为(在此格式中)零被认为是正数,负范围被移位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开始。
缺少的数字是0
。 在数学意义上,0既不是正面也不是负面。 但在二元意义上,由于0
没有负位,因此它被认为是正数。 换句话说,如果你想要-128到128,那么就不会有0。
因为你必须计数0.整数范围[-4,-1](或等效-4,-3,-2和-1)包含4个数字,其余的范围为[0,3](或者,等效地,0,1,2和3)包含4个数字,总共8个,并且3个数字二进制数具有2到3(= 8)个可能组合的幂。
这样想吧。 forms[-n,+ n]的任何整数范围必须具有奇数大小(2 * n + 1个整数)。 无论你使用什么整数二进制表示都会有不同数量的负数和正数,因为组合的数量总是偶数(2的幂)。
那么我们怎么知道两个补码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开始的表示是-4的2位补码表示。