1.概念介绍
首先,我们假设机器存储数字字长是8位。
直接使用表格举例说明概念和计算方式:
概念 | 例1 | 例2 | 例3 | 例4 | 例5 | 例6 | 转换关系 |
真值(十进制) | +0 | -0 | +5 | -5 | +0.5 | -0.5 | 十进制形态下的数字 |
真值(二进制) | +0 | -0 | +101 | -101 | +0.1 | -0.1 | 二进制形态下的数字 |
原码 | 00000000 | 10000000 | 00000101 | 10000101 | 01000000 | 11000000 | 首位是符号位,0正,1负,其他7位存实际值 |
反码 | 00000000 | 11111111 | 00000101 | 11111010 | 01000000 | 10111111 | 正数的反码=原码; 负数的反码是原码符号位不变,其他位取反 |
补码 | 00000000 | 10000000 | 00000101 | 11111011 | 01000000 | 11000000 | 正数的补码=反码=原码; 负数的补码是反码符号位不变,末位加1 |
移码(增码) | 10000000 | 00000000 | 10000101 | 01111011 | 11000000 | 01000000 | 无论正负数, 移码=补码的符号位取反,其他位不变 |
2.详细介绍
真值:无须多说,就是通常我们数学意义上理解的数字;
原码:计算机对数字的定点表示法,首位0或1来表示正或负,其他位来表示数值绝对值大小,通过真值的二进制求解可以直接得到原码数值位的编码;
反码,也是计算机对数字的定点表示法,通常当做原码求补码或补码求原码的中间值;
补码,同样也是计算机对数字的定点表示法,通常,计算机内存中数字的表示方法都是按照补码存储,引入补码的目的,是为了计算机方便对数字进行运算,举例说明:
假设计算机存的是原码,那么:
5 + (-5) = 00000101 + 10000101 = 10001010 = -10
按位相加明显不是正确的,但如果不按位相加,那势必需要用更复杂的逻辑运算,进而提升了计算机硬件开销和设计复杂性;而利用补码做运算,刚好能解决这个问题:
5 + (-5) = 00000101 + 11111011 = 00000000 = 0
我们看到,补码按位相加,高位溢出丢弃后,结果值再根据补码求原码,就能得出值为0,这个结果显然才符合预期;
移码:用补码表示阶码的时候,当阶码无限小,产生了下溢的时候,阶码变成了0,那么这个浮点数的值变为了1,而实际上这个数是无限接近于零,所以引入移码是用来解决浮点数中阶码的问题,规则是,用移码数减1表示阶码,下面用一个例字说明移码在浮点数中的应用:
例:java中用float可以表示浮点数,总共32位,其中首位表示数字的正负,紧接着的8位表示阶码,剩下23位表示尾数精度部分
00000000 00000000 00000000 00000000
我们上面说到,数字在内存中的表示通常按照补码表示,但在浮点数表示里面,只有尾数精度部分才会用补码,而指数部分用移码来表示
我们来算一个数字,如 12.625
整数部分12转为二进制为:1100
小数部分123转为二进制位:101
合并后:1100.101
按照科学计数法的二进制指数形式表示为:1.100101x2^11,其中1.100101是尾数,100101是尾数精度部分,11为指数。
尾数精度部分100101用补码值转为float中23位存储:10010100000000000000000
指数11,补码为 00000011,移码为10000011,移码减1为10000010,放入float阶码位置
最后结果为0 10000010 10010100000000000000000
计算结果可以用java方法验证:Integer.toBinaryString(Float.floatToIntBits(f))