携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,点击查看活动详情
机器数
机器数是将符号"数字化"的数, 是数字在计算机中的二进制表示形式. 机器数有2个特点: 一是符号数字化, 二是其数的大小受机器字长的限制.
根据小数点位置固定与否, 机器数又可以分为定点数和浮点数. 通常, 使用定点数表示整数, 而用浮点数表示实数.
在计算机用一个数的最高位存放符号, 正数为0, 负数为1.
在计算机中 这和计算机 字长(位数) 相关.
例如:
计算机字长为4位时:
+3=0011
-3=1011
真值(机器数的真值)
就是真正的数值. 比如 -1,-2,+1,+2;
计算机字长为4位时:
0011 的真值 +3
1011 的真值 -3
整数
原码
最高位为符号位, 0代表正数, 1代表负数, 非符号位为该数字绝对值(真值的绝对值)的 二进制 表示;
计算机字长为4位时:
+3的原码为 0 011
-3的原码为 1 011
因为第一位是符号位, 所以8字长二进制数的取值范围就是:[1111 1111 , 0111 1111], 也就是[-127 , 127];4字长二进制数的取值范围就是:[1111 , 0111], 也就是[-8 , 7];
原码的符号位不能直接参与运算(有负数时), 必须和其他位分开, 这就增加了硬件的开销和复杂性
反码
正数的反码是其本身
负数的反码是在其原码的基础上, 符号位不变, 其余各个位取反.
在4位机器上
补码(也是机器使用的)
正数的补码就是其本身.
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
在4位机器上
使用
原码的符号位不能直接参与运算, 必须和其他位分开, 这就增加了硬件的开销和复杂性.
因此有了反码.
在4位机器上:
这里出现了一个问题, 这里出现了 -0 和 0.
当用反码计算两正数相减时, 2-1=3+(-1)=[0 010]{原} + [1 001]{原}=[0 010]{反}+[1 101]{反}=[1111]{反}=[1 000]{原}.显然这也是错误的.
由此加入了补码:
溢出及补码溢出的判断
无论采用何种机器数, 只要运算的结果大于数值设备所能表示数的范围, 就会产生溢出. 溢出现象应当作一种故障来处理, 因为它使结果数发生错误.
只有真正意义上的相加出现的溢出才需要处理, 比如: 正+正, 负+负, 正-负, 负-正.
- 不是同号数相加, 则不可能溢出, 但有可能出现正常进位;
- 同号数相加有可能溢出;
- 同号数相加, 如果结果的符号位和两加数不同, 既是溢出;
计算机判断:
查其最高位和次高位的进位位:
- 均无进位产生 ,结果正确
- 均产生进位, 符号位进位自然丢失, 结果正确
- 只有一位产生了进位,会出现溢出或进位到符号导致符号错误
此即为判断机器是正常进位还是溢出的基本依据,在微型机中可用异或电路来实现上述的判断.
表示0, 那么 也可以表示另外一个数 , 即最小值
因为机器使用补码, 所以对于32位int类型, 可以表示范围是: 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.
原理
问题: 为什么使用补码可以计算出正确结果.
同余
当两个整数除以同一个正整数, 若得相同余数, 则二整数同余. 记作 a ≡ b (mod m).读作 a 与 b 关于模 m 同余.
求模: 对于正数实际上就是余数.
公式(正负通用):
其中表示取下界.另为表示取上界.
取上界(Ceiling):
向0方向舍入取整;
正数: 把小数部分全部去掉后加;
负数: 把小数部分全部去掉. 即所有数都是趋进于0.
取下界(Floor):
向负无穷方向舍入取整;
正数: 把小数部分全部去掉;
负数: 把小数部分全部去掉后减1. 即所有数都是取小.
不同的语言对求模结果不相同. 对于C/Java 类型语言一般是取上界.
例如:
4 mod 12 = 4
16 mod 12 = 4
28 mod 12 = 4
解决
关键在于让-3(负数)变成一个正数, 加完以后和原来直接相加结果一样.
首先, 如过没有条件限制这是不可能的; 在计算机中有字长限制, 如 32位,64位等, 限制了一个数字最大有多大.
先看一个简单的例子:
在一个钟表中, 如果当前时间是6点, 希望将时间设置成4点, 需要怎么做呢?
- 回拨(2-12n)个小时:6-2-12n
- 往前拨(10+12n)个小时(n>0, n 是正整数):6+10+12n
由1,2 可知 1的减法可以由2的加法代替. 2 实际上是取模运算. 回拨2小时等同于前拨10小时
(6+10+12n) mod 12 =4(n>0, n 是正整数)(这一组数也叫剩余类);
根据同余性质:
反身性: a ≡ a (mod m)
保持基本运算性质:
2 ≡ 2 (mod 12)
(-2) ≡ 10 (mod 12)
6 - 2 ≡ 6 + 10 (mod 12)
-2 模12的正同余数之一是10, 即6 - 2 与 6 + 10 模 12的结果相等.
以4位机器二进制为例:
如果将认为是原码,则, 由于算机在运算时并不辨别符号位, 所以可看作12. 同样4位字长机最大数为16(16个数).
(-3) mod 16 = 13 // 真值
12 mod 16 = 12 // 反码
13 mod 16 = 13 // 补码
12 mod 15 = 12 // 反码mod15
-3 mod 15 = 12 // 真值mod15
这里可以看到只有补码与真值模16时是同余, 事实上, 正数的反码对应的无符号数与真值是关于16同余的, 而负数的反码对应的无符号数却与真值关于15同余.
重点: 实际上一个正数的反码, 是这个数对于一个 模 的同余数. 这个 模 对应 计算机字长 中所能表示的最大值. 为了解决负数的问题引入了补码, 对于补码在反码的基础上+1, 其实是解决0 这个数字造成的问题, 因为没有-0.