32位intel的CPU中,int类型为什么最小值为-(2^31) ?
最近在看《深入理解计算机系统》,里面说,在32位计算机中,对于int类型,最小值是通常为-(2^31)
用二进制补码表示是[1000...0000]
而我觉得最小值
用二进制补码表示应该是[1000...0001]
也就是-(2^31)+1
按照补码的运算规则,[1000...0000]的值应该也是0吧?
诸位帮我解释一下。
[ 本帖最后由 janusle 于 2007-3-22 21:25 编辑 ]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
其实二进制补码还有一个更简单的计算方法:
以 32 bit 的位模式为例. 假设其最高位(即最左边的bit 位, 也即符号位)为 s, 该 32 bit 位模式按无符号二进制数解释表示的十进制数为 b, 则该位模式按照二进制补码解释表示的十进制数即为 b - s * 2^32.
按照这种解释, 应该就很清楚了. 另外, 这种解释在 <<深入理解计算机系统>> 里面也是有说到的.
[ 本帖最后由 MMMIX 于 2007-3-23 04:37 编辑 ]
不用想那么复杂,拿 4 位值来举个例子
MSB 为符号位,那么,很明显:
正数的取值范围是: 0 000 ~ 0 111, 也就是说最小值是 0 , 最大值是 7
负数的取值范围是: 1 000 ~ 1 111, 也就是说最小值是 1000(-8), 最大值是 1111 (-1)
1000 为什么是 -8,可以简单算一算
1 000
取反 0 111
+ 1
-----------------
1000 符号位为负,所以是 - 8
我不赞同这种解释。
我学微机原理的时候好像说得是因为+0和-0是一样的,浪费一个编码,就把-0规定成-2^31啦~反正所谓的编码都是人为规定的嘛~就当是反码规定的一部分喽~
以 4 位为例,我的理解是:
有符号数原码:
0 000 ~ 0 111 +0 ~ +7 前面的 0 表示是正数。
1 000 ~ 1 111 -0 ~ -7 前面的 1 表示是负数。
因为 +0 和 -0 实际上是相等的,也就是说,0 用原码表示的话有两种方式,这样的编码虽然人看起来要好懂一些,但是对于计算机来讲,有三个坏处:
1,违反了唯一性
2,浪费了一个位模式(排列方式)。因为理论上来讲 4 位二进制能表示 2^4 = 16 个不同的数,但是这里只表示了 -7 ~ +7 15 个数。
3,-7 明明是小于 -0 的,但是如果不把最高位当作符号位来看的话,1000 要比 1111 小。
我着重讲一下第三点。因为我们最终的目标是让符号也能够参与运算,也就是说,任何两个有符号数比较大小的时候,我们希望只需要减一下就可以了,因此原码的 1000 和 1111 它的顺序是反的,很不利于运算。
-128 在原码里是无法表示的。
基于以上三个原因,就引进了补码,在介绍补码之前,我先介绍一下反码:
正数的反码就是原码:
0 000 ~ 0 111 +0 ~ +7 反码
负数的反码就是对原码除符号位以外的其余各位进行取反:
1 111 ~ 1 000 -0 ~ -7 反码
这么做的好处是什么呢?好处是,解决了上面三个问题中的第三个问题。
但是另外两个问题还是没有解决。
下面引入的补码,就是为了解决另外两个问题。
补码:
补码的规则是:正数的补码和原码、反码形式相同。
负数的补码,等于反码 + 1,加 1 的时候,符号位也参与运算,溢出位被丢弃,不影响结果。
也就是说:
0 000 ~ 0 111 +0 ~ +7 补码
(1)0 000 ~ 1 001 -0 ~ -7 补码。
注意反码的 -0 也就是 1111 加了 1 之后,符号位产生了进位,溢出了,溢出之后,剩下的部分正好和 +0 一样了。
也就是说,第一个问题也解决了。
第一个问题解决了,那么就剩下第二个问题了,
因为从 -0 到 -7 依次是:
-7: 1 001
-6: 1 010
-5: 1 011
-4: 1 100
-3: 1 101
-2: 1 110
-1: 1 111
-0: 0 000
+1: 0 001
+2: 0 010
...
...
...
也就是说,还剩下 1 000 这个位模式是没用的,
因此就可以用它来表示其它的数。但是到底应该用它来表示 +128 好呢?还是 -128 好呢?
观察上面的序列,你会发现,如果溢出是正常的话,
上面的数列正好是连续的,
而 1 000 比 1 001 还要小 1,因此用来表示 -128 是合理的。加 1 之后正好等于 -127。
因此就用 1 000 来表示 -128 了。
[ 本帖最后由 flw 于 2007-3-23 14:29 编辑 ]
受教了,感谢flw,感谢mik,感谢诸位
说得确实精彩。
计算负数补码的值是很简单的,有一个公式,就以上例 4 位数(1000)为例:
公式为: ( X3 * - 2^(n-1) ) + ( X2 * 2^(n-2) ) + ( X1 * 2^(n-3) ) + ( X0 * 2^(n-n))
= (1 * - 2^3) + (0 * 2^2) + (0 * 2^1) + (0 * 2^0)
= -8 + 0 + 0 + 0
= -8
每个式子的结果都是可以计算出来的。
所以:
1000
~ 0111
+ 1
--------------
- 8 (由于上述公式所述,就是因为符号位为负,即等于 -8 )
或许大家理解不同,但我偏重于实际。
[ 本帖最后由 mik 于 2007-3-23 21:28 编辑 ]
请问在你的这个式子中,第一个 1000 是什么码?0111 是什么码?第二个 1000 又是什么码?
汗~~ 你还在抓概念
1、
你的精彩理论的论述,我相信在大多数计算机基础的书籍都能找到。关键是灵活掌握,总结适合自己的方法。
况且,你最后给出的答案是错误的。1000 居然等于 -128
我所说的式子是我自己总结出来的一种计算方法,并不能涉及概念性问题。我并没有对式子中的哪个数作“定义性”的描述,只是说“取反”,“+1”。只是计算的方法而已。是方便我计算的。式子中第1个1000是补码,正确来说是“2的补码”,0111是反码,正确来说是“1的补码”,第二个1000我说不出来。
比较正规的计算方法,如我所说的:
复制代码
另一个简单方法,可以:
复制代码
2、你所说的人为规定我并不赞同。只有两种情况下才会有 +0 以及 -0 存在,就是浮点数
对单精度数来说:
复制代码这种情况是并存的,并不矛盾。
就拿 8 位数来说:
10000000 = -128,是通常计算出来的,不是“用来表示-128”这种概念
对符号数来说:10000000 就是个模值。-1 回卷0111 1111(127) +1 进值 10000001 (-127)