1.原码
原码在存储方式上,最高位是符号位,其他位是数值位。
如 :
正数原码:
3 对应的一个字节的原码:0000 0011B
负数原码:
-3 对应的一个字节的原码:1000 0011B
特殊点的是0的存储,0有两种存储方式:
+0 对应的一个字节的原码:0000 0000B
-0 对应的一个字节的原码:1000 0000B
注:计算机中的负数不是以原码的方式存储的,而是补码。
2.反码
反码在存储方式上也是最高位时符号位,其他位是数值位。
如:
正数反码:
3 对应的一个字节的反码:0000 0011B //没错,反码正数的表示方式跟原码是一样的
负数反码:
-3 对应的一个字节的反码:1111 1100B //负数则符号位为1,数值位是原码的按位取反
特殊点跟原码一样,0的存储在反码也有两种存储方式:
+0 对应的一个字节的反码:0000 0000B
-0 对应的一个字节的反码:1111 1111B
3.补码
补码在存储方式同上,最高位时符号位,其他位是数值位。但是, 最高位既是符号位,也是数值位。
如:
正数补码:
3 对应的一个字节的反码:0000 0011B //没错,补码的正数与原码、反码一样。
负数补码:
-3 对应的一个字节的反码:1111 1101B //负数则符号位为1,数值位是反码加上1
求补码的负数过程即:
(1)先求反码
(2)求得的反码加上1
(3)完成
如已知的一个负数的把补码是0XFFFF,想要知道它是负多少,可以这么求:
1111 1111 1111 1111B
反码得:
0000 0000 0000 0000B
加1得:
0000 0000 0000 0001B
得出:
1D
再加上它表示的是一个负数的,所以结果是-1D。
补码的0就只有一种存储方式:0000 0000B
计算机的数值就是采取补码的方式存储的。
总结:原码、反码、补码在正数的存储方式上是一样的。不同的是负数,不过也有一点共同点,就是符号位都是用1来表示这个数是负数。同时,以上三种编码方式称为定点数。
4.移码(增码)
关于移码我查询了很多资料,因为浮点数的阶码是采取移码方式存储的。
但是阶码的移码跟普通的移码不太一样,采取的是127移码,即在原数加上127。而通常的移码是加上128移码。即补码的符号位取反。
看例子:
普通的移码换算:
3D
0000 0011B
符号位取反
1000 0011B
当然,你也可以这么算 3 + 128 = 131。 131D = 1000 0011B
浮点数中阶码的移码换算
3D
0000 0011B
先减一
0000 0010B
符号位取反
1000 0010B
同理,你也可以这么算 3 + 127 = 130. 130D = 1000 0010B
注: 移码中符号位0表示负数, 1表示正数
4.数值的存储方式
4.1 正数,字符
好了,理解了上面就可以看计算机是怎么存取数值的。
对于 int short long 的存储方式,采用的是补码
short i = 3;
i在内存中实际上存的是 0000 0000 0000 0011B
而
short i = -3;
采取补码的方式,即 1111 1111 1111 1101B
而对于unsigned 类型,数的存储也是一样的。不过
1111 1111 1111 1101B将不解释为-3,而是65535
字符有一套编码,称为ASCII编码,每一个字符对应着一个编码,关于ASCII的编码表我就不贴出来了。
举几个例子:
'0'这个字符在编码上是 30H, 所以计算机在存储的时候存的是 30H
‘a’这个字符在编码上是 61H, 所以计算机在存储的时候存的是 61H
‘\0’这是一个字符,这个字符在编码上是 0H,所以计算机直接存0进去。
注意的是,字符'0'并不等于数值0。
4.2 浮点型
浮点型的存储采取的是IEEE754标准。分为三部分(float为例):
符号位 阶码 尾数
31(1位) 30 ~ 23(8位) 22 ~ 0(23位)
符号位容易理解, 1 负数, 0正数
阶码:
如 123.456
可以表示为 1.23456 * 10^2 这个2表示的就是阶码了。
尾数就是实际上的数值了。不过,要注意,尾数第22 位前面,也就是最高位前面隐藏着一位 1。
例1:
1.0
计算机浮点数存储中是 0 00000000 0000 0000 0000 0000 0000 000B
也就是 0X00000000
what?
因为尾数的最高位前面隐藏着一位 1 .
0 符号位
0000 0000 阶码 等于 10^0 = 1
1.0000 0000 0000 0000 0000 000 尾数
所以 尾数×阶码 = 1.0
这个1怎么来的?其实我也不知道,IEEE754的规定把尾数的前面还有个隐藏的1。如果有哪位同学知道的也请告诉我一声 。 thanks~~
例2:123.456这个数用二进制怎么存?
首先,它是一个正数 ,所以符号位为 0。
先别管阶数。
123D 换为二进制是: 1111011B
0.456怎么换为二进制?当然,这是有公式的。公式就是把小数点后的值不断乘以2
0.456 × 2 = 0.912
0.912 × 2 = 1.824
0.824 × 2 = 1.648
0.648 × 2 = 1.296
0.296 × 2 = 0.592
0.592 × 2 = 1.184
0.184 × 2 = 0.368
0.368 × 2 = 0.736
0.736 × 2 = 1.472
0.472 × 2 = 0.944
0.944 × 2 = 1.888
0.888 × 2 = 1.776
0.776 × 2 = 1.552
0.552 × 2 = 1.104
0.104 × 2 = 0.208
0.208 × 2 = 0.416
....
//这个数举得不好,后面我就不贴出来算了。直接贴换算结果:
0.456 = 0.01110100101111001B
123.456 = 1111011.01110100101111001B
也等于:
1.11101101110100101111001B 这个数就是尾数了。
阶码就是6,不过6要换成移码 即 6 + 127 = 133 = 100110011B
所以123.456存为
0(符号位) 100110011(阶码) 11101101110100101111001(尾数)。注意,尾数最高位有隐藏一位1
例3:已知二进制求浮点数
还是以123.456上面举例
0 100110011 11101101110100101111001B
先看尾数
11101101110100101111001B
加上隐藏的1
1.11101101110100101111001B
阶码
100110011B = 133D
133 - 127 = 6
整理加上阶码后的尾数
1111011.01110100101111001B
算小数点的左边
1111011 = (1 * 2^6) + (1 * 2^5) + (1 * 2^4) + ( 1* 2 ^3) + (0 * 2^2) + (1 * 2 ^ 1) + (1 * 2^0) = 64 + 32 + 16 + 8 + 0 + 2 + 1 = 123
算小数点的右边
01110100101111001 = (0 * 2^-1) + (1 * 2^-2) + .... = 456001
后面多出001是因为浮点型是不稳定的存储方式,在运算的过程中存在偏差。所以浮点数运算是一件比较危险的事情。刚好在这个例子中遇到了。真是幸运!
好了,符号位是0,表示为正。最后终于可以得出 0 100110011 11101101110100101111001B = 123.456F。