二进制小数与浮点数的存储

2023-08-31  本文已影响0人  李不言被占用了

小数二进制的转换和浮点数的存储是两个不太相关的内容,所以本文分两个主题分别记录。

进制转换

十进制整数转二进制

除二取余法,余数倒排。
原理来源于:
十进制:123=1*10^{2}+2*10^{1}+3*10^{0}
二进制:1011=1*2^{3}+0*2^{2}+1*2^{1}+1*2^{0} = 11
反向求解的时候就是除2(基数)取余。

11 ÷ 2 = 5 余 1
5 ÷ 2 = 2 余 1
2 ÷ 2 = 1 余 0
1 ÷ 2 = 0 余 1
得到二进制:1011

十进制小数转二进制

乘二取整。
原理来源于:
十进制:0.123=1*10^{-1}+2*10^{-2}+3*10^{-3}
二进制:0.1011=1*2^{-1}+0*2^{-2}+1*2^{-3}+1*2^{-4} = 0.6825
反向求解的时候就是乘2(基数)取整:

0.6825 * 2 = 1.375  拿走整数部分1,剩0.375
0.375 * 2 = 0.75  拿走整数部分0,剩0.75
0.75 * 2 = 1.5 拿走整数部分1,剩0.5
0.5 * 2 = 1 拿走整数部分1,剩0,结束
得到二进制:0.1011

通过上面的运算可以知道:11.6825转成二进制是:1011.1011
另外一个规律:小数尾数为5(x.5、x.25、x.xxxxx5)才能用完整的二进制表示,不然一直乘2小数部分永远不能为0。
快速运算:

0.1(二进制)=0.5(十进制)
0.01(二进制)=0.25(十进制)
0.001(二进制)=0.125(十进制)
……

小数存储

我们假设,小数点存储在中间,假设用8bit来存储小数:
1011 1011就等于1011.1011。用16bit来存储小数:0000 1011 1011 0000就等于1011.1011。
以上只是我们的假设,为了统一,现在计算机都采用IEEE 754的标准来存储小数(浮点数)。有单精度(32bit)和双精度(64bit)两种。

image.png

统一公式:V=(-1)^s*2^{E}*M
其中s为符号位,E为阶码,M为尾数。
s为所见即所得,0正数,1负数。
E为移码表示,移Bias=2^{N-1}-1,相当于加上2^{N-1}-1,Bias称偏移量。
M为尾数,隐藏最高位1,相当于计算尾数时,要加上1。

以0.4375为例,因为M尾数最高位要为1,也就是我们要想办法让0.4375表示成1.xxx * 2^{E}的形式:0.4375 = 1.75 * 2^{-2}
用单精度表示,偏移量为2^ {8-1} -1 = 127
0.4375 = (-1)^{0} * 2^{-2+127} * 1.75 = 2^{125} * 1.75
现在的任务变成了将125和1.75(需要隐藏高位1,变成0.75)转换成二进制:
125 = 0111 1101(8位)0.75 = 1100 0000 0000 0000 000(23位)
所以0.4375的浮点数表示就是:0011 11110 1110 0000 0000 0000 0000 0000

image.png
在线转换网址

同理,将0011 11110 1110 0000 0000 0000 0000 0000 转换成小数就是:

阶数:0111 1101 = 125,实际 125 - 127(偏移量) = -2
尾数:1100 0000 0000 0000 000 = 0.11(二进制) = 0.5+0.25=0.75(十进制)
尾数补隐藏位1:1+0.75=1.75

原小数:-1^{0} * 2^{-2} * 1.75 = 0.4375

双精度浮点数的偏移量:2^{11-1} -1 =1023

利用java转换

long l = Double.doubleToLongBits(0.4375);
System.out.println(l);
// 11111111011100000000000000000000000000000000000000000000000000
System.out.println(Long.toBinaryString(l));

Long aLong = Long.valueOf("11111111011100000000000000000000000000000000000000000000000000", 2);
double v = Double.longBitsToDouble(aLong);
// 0.4375
System.out.println(v);
上一篇下一篇

猜你喜欢

热点阅读