深入了解浮点精度(二。浮点在计算机的存储)

上一章:深入了解浮点精度(一 。有趣的现象)

二进制怎么表示浮点数?

按照2进制,浮点数据可以这么算

4.5 = 100.1 

有的同学可能会问了,100我明白,代表着4,那么小数点后面的那个1为什么能代表0.5?

其实是这么算的,小数点后面的表达式是1/2^n

小数点后面是1 ,那么2的1次方就是2,1/2 = 0.5了。

那么反过来100.01就等于4.25,100.11的0.11 = 0.1 + 0.01 等于0.5 + 0.25 = 4.75

二进制表示浮点数的规范

按十进制来说,550 = 5.5 * 10^2

那么二进制的浮点也可以这样表示

4.5 = 100.1  = 1.001 * 2^2

此时尾数是1.001 ,指数是2.

方程大概如下,但这块不建议你现在看,而是等看完所有章节了再回头看这个方程。

 d.dd...d × βe , (0 ≤ di < β)

其中 d0.dd...d 即尾数,β 为基数,e 为指数。尾数中数字的个数称为精度,每个数字 d 介于 0 和基数β之间,包括 0。小数点左侧的数字不为 0。在二进制里,β=2

我们发现,所有的浮点数都可以表示为1.xxxx *2^N,x只能表示0和1(或许你有其他疑问,但请暂时完全相信这一点,后面我会专门写一章来解释)

因此,在实际存储中,我们会省略掉最前面的1,直接拿到小数点后面的当作尾数。

那么在计算机里存储就大概是这样的,下面是个float类型的存储

 

+- 1 2 3 4 5 6 7 8                                              

float一共32位。

其中第一位是符号位,2~9符号位位是指数位,后面的是尾数位。

我们来测试一下,边看现象,边说明:

public class Test1 {
	public static void main(String[] args) {
		System.out.println("01234567812345678123456781234567");
		p(Integer.toBinaryString(Float.floatToIntBits(4.5f)));//1/2~1
		p(Integer.toBinaryString(Float.floatToIntBits(4.75f)));//1/2~1
		p(Integer.toBinaryString(Float.floatToIntBits(4.25f)));//1/2~2
		p(Integer.toBinaryString(Float.floatToIntBits(4.125f)));//1/2~3
	}
	
	private static void p(String binaryString) {
		int l = 32 - binaryString.length();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < l; i++) {
			sb.append("0");
		}
		StringBuffer append = sb.append(binaryString);
		String string = append.toString();

		System.out.println(string);
	}
}

打印结果:

0 12345678 12345678 12345678 1234567
0 10000001 00100000 00000000 0000000  
0 10000001 00110000 00000000 0000000
0 10000001 00010000 00000000 0000000
0 10000001 00001000 00000000 0000000

说明:

1.最上面打印的01234567812345678123456781234567是为了好观察位数。我们把第一位设置为0,紧挨着的后面8个就是指数,然后再后面的就是尾数。

2.Float.floatToIntBits方法会按float的bit排序生产一个int数。

比如:4.5f的二进制bit排序时0 10000001 00100000 00000000 0000000,那么它就生成一个int数,也是这个排序。

3.Integer.toBinaryString是按二进制打印int数,比如8打印出1000,但由于这个方法会自动忽略前缀所有的0,所以这里写了一个p方法,自动补全到32位,不足长度的在前面补0.

4.前面的指数不看,指数是根反码补码有关的,有兴趣的同学可以了解一下。

5.我们推测4.5 = 100.1 = 1.001 * 2^2。由于舍掉了效数点前面的1,所以尾数应该是001。观察4.5f的尾数,发现正是001

至于指数是2,需要根据反码补码来计算出来,也正是2

6.推测4.75= 100.11 = 1.0011 *2^2,尾数0011也是符合的,进而你可以推断4.125和4.25。

 

这些是最为简单的,告诉你浮点型是怎么存储的,接下来,我们更进一步,来看看浮点型为什么不准确。

深入了解浮点精度(三。浮点不准确)

上一篇:Java位运算


下一篇:[保护模式]联系1 三环访问高2G