原码、反码、补码、移码、浮点数
基本概念及表示范围
定义
- 真值:对于无符号数,真值即对应其十进制数值,对于有符号数,首位为符号位首位为1表示负,首位为0表示正,剩余位为对应十进制绝对值
- 原码:符号位加上真值的绝对值。即用第一位表示符号 其余位表示值。比如如果是8位二进制: +1 = 1000_0001
- 反码:正数的反码是其本身,负数的反码是在其原码的基础上符号位不变,其余各个位取反。
- 补码:正数的补码就是其本身,负数的补码是在其反码的基础上+1
- 移码:真值+偏置值,n位二进制数偏置值为$2^n - 1$,其简单计算方法为补码符号位取反,数值位不变
浮点数
$V = (-1)^S * M * R^E$,如8.345 * 10^0:
- S:符号位,取值 0 或 1,决定一个数字的符号,0 表示正,1 表示负
- M:尾数,用小数表示,例如前面所看到的 8.345 * 10^0,8.345 就是尾数
- R:基数,表示十进制数 R 就是 10,表示二进制数 R 就是 2
- E:指数,用整数表示,例如前面看到的 10^-1,-1 即是指数
例如32位二进制浮点数及可表示为下列格式:
IEEE754标准
- 单精度浮点数 float:32 位,符号位 S 占 1 bit,指数 E 占 8 bit,尾数 M 占 23 bit
- 双精度浮点数 float:64 位,符号位 S 占 1 bit,指数 E 占 11 bit,尾数 M 占 52 bit
为了使其表示的数字范围、精度最大化,浮点数标准还对指数和尾数进行了规定:
- 尾数 M 的第一位总是 1(因为 1 <= M < 2),因此这个 1 可以省略不写,它是个隐藏位,这样单精度 23 位尾数可以表示了 24 位有效数字,双精度 52 位尾数可以表示 53 位有效数字
- 指数 E 是个无符号整数,表示 float 时,一共占 8 bit,所以它的取值范围为 0 ~ 255。但因为指数可以是负的,所以规定在存入 E 时在它原本的值加上一个中间数 127,这样 E 的取值范围为 -127 ~ 128。表示 double 时,一共占 11 bit,存入 E 时加上中间数 1023,这样取值范围为 -1023 ~ 1024。
除了规定尾数和指数位,还做了以下规定:
- 指数 E 非全 0 且非全 1:规格化数字,按上面的规则正常计算
- 指数 E 全 0,尾数非 0:非规格化数,尾数隐藏位不再是 1,而是 0(M = 0.xxxxx),这样可以表示 0 和很小的数
- 指数 E 全 1,尾数全 0:正无穷大/负无穷大(正负取决于 S 符号位)
- 指数 E 全 1,尾数非 0:NaN(Not a Number)
有了这个统一的浮点数标准,我们再把 25.125 转换为标准的 float 浮点数:
- 整数部分:25(D) = 11001(B)
- 小数部分:0.125(D) = 0.001(B)
- 用二进制科学计数法表示:25.125(D) = 11001.001(B) = 1.1001001 * 2^4(B)
所以 S = 0,尾数 M = 1.001001 = 001001(去掉1,隐藏位),指数 E = 4 + 127(中间数) = 135(D) = 10000111(B)。填充到 32 bit 中,如下:
相互转换以及运算
二进制十进制转换
整数转二进制
采用”除2取余,逆序排列”法:- 首先用2整除一个十进制整数,得到一个商和余数
- 然后再用2去除得到的商,又会得到一个商和余数
- 重复操作,一直到商为小于1时为止
- 然后将得到的所有余数全部排列起来,再将它反过来(逆序排列),切记一定要反过来!
假设我们现在需要将42转为二进制,那我们怎么做呢,如下图所示:
小数转二进制
采用”乘2取整,顺序排列”法:- 用2乘十进制小数,可以得到积,将积的整数部分取出
- 再用2乘余下的小数部分,又得到一个积,再将积的整数部分取出
- 重复操作,直到积中的小数部分为零,此时0或1为二进制的最后一位,或者达到所要求的精度为止
例如将0.125转换为二进制:
- 0.125 * 2 = 0.25 ——0
- 0.25 * 2 = 0.5 ——0
- 0.5 * 2 = 1.0 ——1
当小数部分为0就可以停止乘2了,然后正序排序就构成了二进制的小数部分:0.001
如果小数的整数部分有大于0的整数时,将整数部分和小数部分先单独转为二进制,再合在一起就可以了,
例如:假设要将8.125 转换为二进制
- 现将8转为二进制:得到1000
- 再将0.125转为二进制:得到0.001
- 合并后为1000.001
二进制转十进制
以小数点左边一位为0,往左位阶依次是$2^1,2^2…$,往右是$2^{-1}, 2^{-2}…$,依次相乘并加和即可
原码、反码、补码、移码相互转换
原码 | 反码 | 补码 | 移码 | |
---|---|---|---|---|
正整数 | 本身,符号位为0 | 与原码相同 | 与原码相同 | 符号位取反 |
负整数 | 本身,符号位为1 | 符号位不变,数值位按位取反 | 反码末位加1 | 符号位取反 |
正小数 | 本身,符号位为0 | 与原码相同 | 与原码相同 | 小数无移码 |
负小数 | 本身,符号位为1 | 符号位不变,数值位按位取反 | 反码末位加1 | 小数无移码 |
表示范围
设有一个n位二进制数
表示范围(机器字长为n + 1) | 特征 | |
---|---|---|
整数原码 | $-(2^n -1)\le x \le 2^n - 1$ | 0的表示方法有两种,原点对称 |
小数原码 | $-(1 - 2^{-n}) \le x \le 1 - 2^{-n}$ | 0的表示方法有两种,原点对称 |
整数反码 | $-(2^n -1)\le x \le 2^n - 1$ | 0的表示方法有两种,原点对称 |
小数反码 | $-(1 - 2^{-n}) \le x \le 1 - 2^{-n}$ | 0的表示方法有两种,原点对称 |
整数补码 | $- 2^n \le x \le 2^n - 1$ | 真值0只有一种形式,并规定1000,0000表示$x = -2^7$ |
小数补码 | $-1 \le x \le 1 - 2^{-n}$ | 真值0只有一种格式,规定1.000,0000表示x = -1 |
整数移码 | $- 2^n \le x \le 2^n - 1$ | 移码只能用于表示整数,0同样只有一种表示形式,很容易对比大小,移码表示数依次真值递增 |
在现代计算机中,通常用定点补码表示整数 ,用定点原码表示小数 ,用移码表示浮点数的阶码
加减运算
原码加减:
- 原码加减比较麻烦,一般采用补码进行运算
补码加减:
- 直接相加并进位
- 减法等同于加上负数,
- 由$[x]{补}$ 求$[-x]{补}$,将所有位取反,末尾加一
乘法运算
- 原码:符号位和数值位单独运算
- 补码:待补充
除法运算
待补充
符号扩展
- 正数(原、反、补码都一样)最高位进行扩展
- 负数
- 原码:在符号位和数值位之间补0
- 反码:在符号位和数值位之间补1
- 补码:在符号位和数值位之间补1
- 正小数(原、反、补码都一样)末尾进行0扩展
- 负小数
- 原码:末尾补0
- 反码:末位补1
- 补码:末位补0
定点数移位运算
算术移位
- 原码:符号位不参与移位,左移右移都补0
- 反码:符号位不参与移位,左移右移都补1
- 补码:符号位不参与移位,左移补0,右移补1
逻辑移位
可看作对无符号数的移位
循环移位
循环补位,注意进位位