欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

探讨计算机中使用补码表示负数的点滴思考

最编程 2024-07-20 17:03:47
...

这里总结关于为什么负数运算使用补码的一些思考。

问题一:补码是什么?

补码是为了方便计算机对负数进行运算而发明出来的,对于正数没有意义。补码其实就是使用进行运算的数字的模(比如:一个8位二进制的模是1 0000 0000即2^8)减去当前负数的绝对值得到的结果。因为一个负数的绝对值加上他的反码是当前位数所能表示的最大值,也就是摸减去一,所以,一个负数的补码公式为:补码=反码+1。

问题二:为什么负数需要换成补码运算?

一个8位的二进制,最高位0代表正数,1代表负数,那么:

1 + 2 = 3
0000 0001 + 0000 0010 = 0000 0011  //3两个正数相加结果正确
-1 + 2 = 1
1000 0001 + 0000 0010 = 1000 0011 //-3一个负数+正数结果错误
-1 + (-2) = -3
1000 0001 + 1000 0010 = 0000 0011 //3两个负数相加结果错误

由于负数的原码直接参与运算得出的结果都是错误的,所以,现在有两个解决办法:

1.在加法器的基础上再实现一个减法器
2.在不增加减法器的基础上通过其他方法实现负数的运算

总的来说,大佬们采取了后面一种办法来曲线救国,这个就是补码。

1 + 2 = 3
0000 0001 + 0000 0010 = 0000 0011  //3两个正数相加结果正确
-1 + 2 = 1
1111 1111 + 0000 0010 = 0000 0001 //原码1一个负数+正数结果正确
-1 + (-2) = -3
1111 1111 + 1111 1110 = 1111 1101 //将该补码取反加一转换成原码为-3两个负数相加结果正确

那么为什么将负数变成补码就可以正确运算呢?这就要用到模的概念了。
举个比较好理解的例子,时钟。一个时钟有12个大的刻度,假如现在是6点,那么把指针拨到3点有两种办法,一种是逆时针拨动3格,也就是6-3=3,或者顺时针波动9格,即6+9=3(15-12=3),这两种方法是等价的。很明显,时钟的模为12,那么从当前刻度转一圈12刻度其实回到了原点,所以,15点其实就是3点,即6-3=6+(12-3)-12=6+9-12,因为12超出显示范围所以被丢弃,即减去一个数等于加上一个数的补数,同理二进制的负数运算也可以转换成加法。

问题三:计算结果正负以及溢出

先看结果:


Screen Shot 2023-03-09 at 11.56.27.png
1.关于相加结果正负

两个正数相加为正数和两个负数相加为负数,这两个应该没有异议。主要是正数+负数,从操作来看,正负符号相加为1,那么如果最高位进位1和符号位1相加,则为0,结果是正的;如果最高位没有进位,则符号位为1,结果是负的。从原理来讲,正数+负数=正数+补码,有进位说明正数+补码>=模, 因为|负数|+补码=模,那么正数>=|负数|,所以结果为正;同理没有进位说明正数+补码<模,那么正数<|负数|,所以结果为负。

2.关于相加结果溢出

两正数相加,最高位有进位就是超模了,所以,溢出。一正一负相加是不会溢出的,因为结果最大和最小值的绝对值也比模小一。两负数相加,最高位没有进位,说明两负数的补码相加没有超模,那么两负数的原码相加就肯定超模了,因为负数和其补码相加结果等于模,那么两负数加两补码就等于两个模,那么,两负数补码相加没有超模,两负数相加肯定超模,所以,两负数相加,最高位没有进位,结果就溢出了。

问题四:一个8位有符号整型最小值是-128

按照规则一个8位有符号整型的表示范围为:-127~127,但是这里有个问题就是0的唯一性问题,这里1000 0000和0000 0000都表示0,那么运算的时候用哪个表示0比较好,这个计算机无法判断,所以,干脆就把1000 0000表示-128,不仅可以表示多一位数,还可以解决0的唯一性问题,很合理。

以上就是我遇到关于负数补码的一些问题的思考,仅供参考。

参考:为什么计算机中的负数要用补码表示?

推荐阅读