JAVA中的浮点数与二进制

先来看一段简略的代码

public static void main(String[] args) {        System.out.println(0.1+0.2);}

打印后果如下:

0.30000000000000004  //为什么0.1+0.2不等于0.3?

为什么会呈现这种诡异的答案呢?

这还得从浮点数的二进制示意办法说起

这年头儿,连过马路的老奶奶预计都晓得,计算机是采纳二进制计数的

来,简略的考你一下:请把数字15写成二进制的模式

//答案应该比较简单0000 1111

置信你对整数的二进制曾经比拟相熟

但如果我换成小数呢?3.14159265359该怎么示意?

其实,如果不搞底层设计,个别人还真的不太晓得这个答案

但你只有了解小数在二进制中是如何示意的

才可能明确文章结尾的案例【为什么0.1+0.2不等于0.3?】

咱们以小数0.1为例,看看它是如何应用二进制存储的

第一步,把0.1 乘以 2, 失去的后果0.2,  整数局部 0 取走第二步,把上一步留下的小数局部0.2,乘以2,失去的后果0.4,  整数局部 0 取走第三步,把上一步留下的小数局部0.4,乘以2,失去的后果0.8,  整数局部 0 取走第四步,把上一步留下的小数局部0.8,乘以2,失去的后果1.6,  整数局部 1 取走......直到,小数局部为0

下图展现了计算的过程 ↓

最终的二进制,就是整数局部的合集

写进去大略是这样:

0001 1001 1001 1001 1001 ...

能够看到,1001 的局部,是有限循环的

咱们用二进制的小数把它写进去大略是这样

0.0001 1001 1001 1001 1001 ...

它相当于

你会发现,它并不等于0.1

它只是一个近似值

所以,二进制保留的位数越多,精度也就越高


晚期的计算机其实是不能解决浮点数的

直到IEEE 754 规范呈现后,计算机能力解决浮点数

依据IEEE 754 规范,float类型,共4个字节,32个bit位

其中指数局部占8位,小数局部占23位

那么 指数局部小数局部 别离用来保留什么呢?

咱们仍然以 数字 0.1 为例,咱们方才曾经失去了它的二进制

0.0001 1001 1001 1001 1001 ...

依照IEEE 754规范,咱们须要把它的小数点,向右挪动

直到整数局部是1为止

0.0001 1001 1001 1001 1001 ...//小数点向右挪动4位//相当于乘以2的4次方0001.1001 1001 1001 1001 ...//也就是1.1001 1001 1001 1001 ...//为了维持数字大小不变//再乘以2的-4次方

最终变成

float小数局部只能保留23位

-4 就是 指数局部

1001......就是 小数局部

小数点的地位不是固定的,而是浮动的,故名:浮点数


理解到这一点,你就可能承受更多看起来奇怪而乏味的景象

比方

float f1=0.4f;double d1=0.4;System.out.println(f1==d1);//falseSystem.out.println(f1>d1); //true

f1还原为10进制,后果为0.40000000596046450000

d1还原为10进制,后果为0.40000000000000000000


对于二进制的底层,还有很多问题,有待咱们摸索

多理解一点,就少一些困惑