0.1 + 0.2 != 0.3:Is floating point math broken?

本文收錄于 www.cswiki.top
看下面這段代碼
0.1 + 0.2 == 0.3 -> Output: false
0.1 + 0.2 -> Output: 0.30000000000000004
0.1 + 0.2 != 0.3,什么情況?
先上答案:0.1 + 0.2 != 0.3 這個(gè)問題的癥結(jié)在于:在現(xiàn)今的計(jì)算機(jī)中,數(shù)字的最終存儲(chǔ)(表示)格式是二進(jìn)制,是整數(shù)乘以 2 的冪。所以一切分母不是 2 的冪的有理數(shù)(例如 0.1,即 1/10)都是無法被計(jì)算機(jī)精確表示的。
下面來詳細(xì)分析:
十進(jìn)制小數(shù)與二進(jìn)制的轉(zhuǎn)換
整數(shù)十進(jìn)制轉(zhuǎn)二進(jìn)制大伙都知道(除 2 取余法),我們來看看小數(shù)是怎么轉(zhuǎn)二進(jìn)制的
小數(shù)部分的轉(zhuǎn)換不同于整數(shù)部分,它采用的是乘 2 取整法:將十進(jìn)制中的小數(shù)部分乘以 2,得到一個(gè)數(shù),將這個(gè)數(shù)的整數(shù)位作為二進(jìn)制的一位,然后繼續(xù)取其小數(shù)部分乘以 2 作為下一位,直到不存在小數(shù)為止
舉個(gè)例子:3.14(十進(jìn)制)
整數(shù)部分:
3(十進(jìn)制)-> 0011(二進(jìn)制)
小數(shù)部分:
0.14 x 2 = 0.28(將十進(jìn)制 3中的小數(shù)部分0.14乘以 2,得到一個(gè)數(shù)0.28,將這個(gè)數(shù)的整數(shù)位0作為二進(jìn)制的一位,然后繼續(xù)取其小數(shù)部分乘以 2 作為下一位,直到不存在小數(shù)為止),此時(shí)小數(shù)部分的二進(jìn)制表示是0xxx xxxx0.28 x 2 = 0.56(將十進(jìn)制 0.28中的小數(shù)部分0.28乘以 2,得到一個(gè)數(shù)0.56,將這個(gè)數(shù)的整數(shù)位0作為二進(jìn)制的一位,然后繼續(xù)取其小數(shù)部分乘以 2 作為下一位,直到不存在小數(shù)為止),此時(shí)小數(shù)部分的二進(jìn)制表示是00xx xxxx0.56 x 2 = 1.12(將十進(jìn)制 0.56中的小數(shù)部分0.56乘以 2,得到一個(gè)數(shù)1.12,將這個(gè)數(shù)的整數(shù)位1作為二進(jìn)制的一位,然后繼續(xù)取其小數(shù)部分乘以 2 作為下一位,直到不存在小數(shù)為止),此時(shí)小數(shù)部分的二進(jìn)制表示是001x xxxx.......
問題就出現(xiàn)了~
如果小數(shù)部分一直沒法變成 0,那么小數(shù)部分的二進(jìn)制表示將是無窮無盡的。
由于計(jì)算機(jī)的資源是有限的,所以沒辦法用二進(jìn)制精確的表示這些小數(shù)部分一直沒法變成 0 的數(shù),只能用【近似值】來表示(現(xiàn)在基本采用的都是 IEEE 754 標(biāo)準(zhǔn),https://en.wikipedia.org/wiki/IEEE_754#Basic_and_interchange_formats),這不可避免地就會(huì)造成精度缺失
Working with Floats in Programming
在平常寫代碼的時(shí)候,這個(gè)精度問題意味著我們需要使用舍入函數(shù)將浮點(diǎn)數(shù)四舍五入到我們需要的小數(shù)位,然后再顯示它們。
還需要用【允許一定差距(allow some amount of tolerance)的比較】來替換浮點(diǎn)數(shù)之間的相等比較 ==,這意味著:
不要使用:if (x == y) { ... }
而是使用:if (abs(x - y) < myToleranceValue) { ... }
心之所向,素履以往,我是小牛肉,小伙伴們下篇文章再見
回復(fù)『春秋招』我拉你進(jìn)交流群
