深入瞭解浮點精度(三。浮點不準確)

上一章:深入瞭解浮點精度(二。浮點在計算機的存儲)

通過上章,我們知道,4.25的二進制是100.01,4.75 = 100.11。

但仔細想想,就會覺得不對勁,

浮點是不是隻能表示1被2或2的倍數除的小數和呢?

帶着這個疑問,我們來拜訪下4.1,這次我們和4.125以及4.0625一起來拜訪

0 12345678 12345678 12345678 1234567

0 10000001 00001000 00000000 0000000    4.125
0 10000001 00000110  01100110 0110011     4.1
0 10000001 00000100 00000000 0000000    4.0625

在打印裏,我們發現4.1大於4.0625,小於4.125.這也符合我們的常識。

其中4.625和 4.125和4.25一樣比較特殊,都可以表示1被2或2的倍數除的小數和呢.所以在二進制裏,它的描述很簡單,很快就到了盡頭。

但是4.1就不一樣了,無論怎麼搞,會發現都無法找到盡頭,如果位數是無限的,它可以搞到無限位,但最終都是越來越接近1,就像高等數學的極限一樣,下面類似下面這個公式

1 = 1/2 + 1/4 + 1/8 +......1/n+.......

可是你雖然無限位,但電腦存儲可達不到無限位了,怎麼辦呢?這就牽涉到精度的問題了。

規定只存儲一定量的尾巴,多餘的尾巴不要。

如float類型,尾數位置是32-8-1 = 23尾。

那麼它只能存儲23位的尾數,所以這就是它的精度,再往後的無限循環或者有限的尾巴我就不表示了,我就表示這麼多。

那麼由此我們可以得出,double類型雙精度確實比float精度要高的多,因爲它的尾數位更長。

 

可以這樣又引出了另一個問題。

我們來嘗試打印一下4.0999999f的位

0 12345678 12345678 12345678 1234567

0 10000001 00001000 00000000 0000000    4.125
0 10000001 00000110  01100110 0110011     4.1

0 10000001 00000110  01100110 0110011     4.0999999f
0 10000001 00000100 00000000 0000000    4.0625

這時候就會發現,我去,這4.1和4.0999999是一模一樣的嗎?

不,它們不是一樣的,只是可憐的是,它們在有限的23尾內是一樣的,float類型就只能存儲這麼多

我們再測試一下這個:

System.out.println(4.1f == 4.0999999f);

結果是true

哈哈哈哈~~~是不是再也不敢再用浮點數據類型了?

well,沒有辦法,就是這樣,你平時所用的浮點數據類型就是這樣,它不會考慮精度之外的數,因爲本身它也從來沒有存儲過。

事實上,System.out.println(4.1f == 4.0999999f);這句會報黃線,編譯器認爲是沒有意義的代碼。相當於true==true

 這個時候,我們再來看看第一章的一個現象:

 System.out.println(0.05 + 0.01);

0.060000000000000005

爲什麼會出現這種現象呢?現在就可以推測解釋了。

在計算機裏,不是0.05+0.01,很有可能是0.049999999998 + 0.01000000007(數據不準,只是說明思想)

 

看到浮點數如此坑爹,有的同學可能不淡定了,那該怎麼辦呢?

我平時該怎麼對浮點型的數據進行運算呢?請看下一章。

深入瞭解浮點精度(四。嚴格精度的浮點運算)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章