今天我们来解决0.1d+0.2d==0.3d是false的问题!

简介: 今天我们来解决0.1d+0.2d==0.3d是false的问题!
之前文章给大家做了一些测试题,如果全对的话,说明你底子很厚,如果有出错的话也很正常,毕竟谁都有遗漏的知识,谁都有忘记的,回头再看一遍让自己记住就可以了,没有什么可气馁的(这是偷偷地说给我自己听得,哈哈) 正如标题一样,下面的公式为什么是false
double a = 0.1d;
double b = 0.2d;
double c = 0.3d;
System.out.println((a + b) == c);
System.out.println((0.1d + 0.2d) == 0.3d);
要了解这个,我么先的了解了解IEEE 754,何为IEEE 754呢? IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。(百度百科,在写这个文章之前,鬼知道什么是IEEE 754但是,现在我知道了。而且为了了解这个我竟然想了好几天)_地址:http://www.softelectro.ru/ieee754_en.html_不论怎么样,计算机存储都是二进制的,所以要想看下去,就必须知道知道十进制转二进制,整数转二进制除以2求余,小数转二进制正好相反小数乘以2取整,例如IEEE 754例子一样155.625转成二进制是什么呢?

先算155


155 -> 155 / 2 = 77 --- 1
77 -> 77 / 2 = 38 --- 1
38 -> 38 / 2 = 19 --- 0
19 -> 19 / 2 = 9 --- 1
9 -> 9 / 2 = 4 --- 0
4 -> 4 / 2 = 2 --- 0
2 -> 2 / 2 = 1 --- 0
1 -> 1 / 2 = 0 --- 1
155 = 1 * 2^7 + 0 * 2^6 + 0 * 2^5 + 0 * 2^4 + 1 * 2^3 + 0*2 ^ 2 + 1 * 2^1 + 1 * 2^0  
所以二进制是 10001011

在算0.625

0.625 -> 0.625 * 2 = 1.25 --- 1
1.25 -> 0.25 * 2 = 0.5 --- 0
0.5 -> 0.5 * 2 = 1.0 --- 1
0.625 = 1 * 2^-1 + 0 * 2^-2 + 1 * 2^-3
所以二进制是0.101

所以

155.625十进制等于1001101.101二进制
1.55625 * 10 ^2 = 1.001101101 * 2^111(二进制) = 1.001101101 * 2^7

640.png
这个图看懂了吗?我感觉一篇文章说不完。。。

浮点数类型

640.jpg

单/双精度浮点数分别对应java语言中的float和double

单精度浮点数

640.jpg

双精度浮点数

640.jpg
S代表符号位,0代表正,1代表负
E代表指数,b代表指数有多少位
M为尾数,n代表尾数有多少位

现在我们回归正题

0.1 转成计算机语言应该是多少呢?

0.1 -> 0.1 * 2 = 0.2 取 0
0.2 -> 0.2 * 2 = 0.4 取 0
0.4 -> 0.4 * 2 = 0.8 取 0 
0.8 -> 0.8 * 2 = 1.6 取 1
0.6 -> 0.6 * 2 = 1.2 取 1
0.2 -> 0.2 * 2 = 0.4 取 0
0.4 -> 0.4 * 2 = 0.8 取 0 
0.8 -> 0.8 * 2 = 1.6 取 1
可以看出来循环
得到的结果是
0 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011...
二进制0舍去,但是这是小数又因为保留52位(这里来说double)所以得到
1.1 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011  010 * 2^-4
(因为无限循环,又因逢1进位所以)
这把用计算机储存标识应该是什么呢
F = (-1)^0 * 2^(-1020) * (1 + 1 0011 0011 0011 .../2^54)

计算只看尾数所以
0.1 = 1.1 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011  010 * 2^-4

0.2雷同得到

0.2 = 1.1 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011  010 * 2^-3

0.1+0.2

0.1 + 0.2 = 
        1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010 * 2 ^ -4 +
       11.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 010 * 2 ^ -4
    = 100.1100 1100 1100 1100 1100 1100 1100 1100 1100 1110 1100 1100 1110 * 2 ^ -4   
    =   1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 (10)  * 2 ^ -2
    =   1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0100  * 2 ^ -2

0.3雷同得到

0.3 = 1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011  * 2 ^ -2

0.1 + 0.2和0.3比较

1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0100  * 2 ^ -2
1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011  * 2 ^ -2

可以看出他们相差了

0.0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001  * 2 ^ -2

这不是2^-54吗?来我们验证下


public static void main(String[] args) {
    double a = 0.1d;
    double b = 0.2d;
    double c = 0.3d;
    System.out.println((a + b) == c);
    System.out.println((a + b) == (c + Math.pow(2, -54)));
}
false
true
学到了吗?当然我讲的只是皮毛毕竟,连接文中我已发,还是靠自己去理解才能真的记忆住,此文只是开篇,更多的东西靠自己去得到。 既然说到这个了如果我在程序中以及用到double和float怎么办?第一种看看有没有所运算,没有做运算double类型用==,或Double.compare(double a,double b)。Double用a.equals(b)或Objects.equals(a,b),如果做运算,只能退而求其次,对于不在乎精确度的项目,Math.abs(a-b)
相关文章
|
2月前
|
缓存 Java API
为什么Java中“1000==1000”为false,而”100==100“为true
为什么Java中“1000==1000”为false,而”100==100“为true
18 0
|
2月前
! [ ] == ! [ ] 和 ! [ ] == [ ] 结果是什么? 为什么?
! [ ] == ! [ ] 和 ! [ ] == [ ] 结果是什么? 为什么?
25 0
|
11月前
|
前端开发
return false得使用
return false得使用
35 0
![] == ![],![] == [],结果是什么?为什么?
![] == ![],![] == [],结果是什么?为什么?
|
缓存 算法 JavaScript
为什么[null] === [null]输出为false❓
有人问,为什么null === null 输出值true,但是[ null ] === [ null ]输出值却是false?
138 0
|
Python
a is b 为 True,a == b 一定为 True 吗?
a is b 为 True,a == b 一定为 True 吗?
93 0
a==b,b==c都为true,那a==c一定为true吗???
a==b,b==c都为true,那a==c一定为true吗???
a==b,b==c都为true,那a==c一定为true吗???
|
存储
什么时候 a == 1 && a == 2 && a == 3 为 true?
什么时候 a == 1 && a == 2 && a == 3 为 true?
110 0
什么时候 a == 1 && a == 2 && a == 3 为 true?
[]==![](true)、{}==!{}(false)
[]==![](true)、{}==!{}(false)
83 0
|
缓存 Java API
为什么 Java 中“1000==1000”为false,而”100==100“为true?
为什么 Java 中“1000==1000”为false,而”100==100“为true?