您現在的位置是:首頁 > 攝影首頁攝影

一道正確率不足30%的Java面試題:浮點數如何正確使用

由 程式設計師架構之路 發表于 攝影2021-06-19
簡介階碼:第2-12位:11111111011尾數:第13-64位:00110011001100110011001100110011001100110011001101總結二進位制不能精確的表示浮點數,所以浮點數不能進行相等的比較

1.0是小數嗎

摘要

本文透過一道面試題來說明浮點數如何正確使用,防止在程式碼中不正確的使用導致業務異常。

在阿里的面試題中有這樣一道題:

一道正確率不足30%的Java面試題:浮點數如何正確使用

據說這道題的正確率不足30%,很多人倒在了這道題上。這道題的正確答案是B,兩者並不相等。同時,根據這個題我們引申出一段常見的程式碼

一道正確率不足30%的Java面試題:浮點數如何正確使用

這是一段錯誤的程式碼,程式碼並不會按照預期的效果進行。那正確應該怎麼使用呢?

一道正確率不足30%的Java面試題:浮點數如何正確使用

1、指定一個誤差範圍,兩個浮點數的差值在此範圍之內,則認為是相等的。

一道正確率不足30%的Java面試題:浮點數如何正確使用

2、使用 BigDecimal 來定義值,再進行浮點數的運算操作。

一道正確率不足30%的Java面試題:浮點數如何正確使用

現在我們來分析一下,為什麼浮點數不能直接比較?

浮點數的二進位制表示

我們都知道,計算機是以二進位制儲存數字的。例如:十進位制的 8 在計算機中以110表示的。

那浮點數0。8如何表示呢?

浮點數二進位制透過”乘2取整“的方法來計算。以題目中0。9為例來說明:

0。9x2=1。8 取整1,小數部分是0。8

0。8x2=1。6 取整1,小數部分是0。6

0。6x2=1。2 取整1,小數部分是0。2

0。2x2=0。4 取整0,小數部分是0。4

0。4x2=0。8 取整0,小數部分是0。8

0。2x8=1。6 取整1,小數部分是0。6

以下開始迴圈

0。6x2=1。2 取整1,小數部分是0。2

0。2x2=0。4 取整0,小數部分是0。4

0。4x2=0。8 取整0,小數部分是0。8

所以,0。9的二進位制表示為 0。111001 1001 … 1001無限迴圈

所以,二進位制無法精確的表示0。9,只能近似的表示。

我們將該二進位制轉化成十進位制是 :

0。1110011001 0。8994140625

0。11100110011001 0。89996337890625

0。11100110011001 0。8999977111816406

一道正確率不足30%的Java面試題:浮點數如何正確使用

題目解答

我們再回到題目:1。0f-0。9f ,並不等0。1f,而是近似的等於 0。1000033

0。8轉化成二進位制為:0。110011001100110011001。。。1001無限迴圈。

所以0。8近似表示為:0。7999992370605469

0。9f-0。8f 近似等於 0。10000054。

所以二者並不相等

一道正確率不足30%的Java面試題:浮點數如何正確使用

計算機中浮點數的表示

float型別在計算機中佔用32位

其中符號位1位,階碼8位,尾數23位

比如0。9

在計算機中存放為:111111011001100110011001100110

符號:第1位:0表示正數,1表示負數;

階碼:第2-9位:11111011

尾數:第10-32位:0011 0011 0011 0011 0011 0

double型別在計算機中佔64位

其中1位符號位,階碼11位,尾數52位

比如0。9

在計算機中存放為:11111111101100110011001100110011001100110011001100110011001101

符號:第1位:0表示正數,1表示負數;

階碼:第2-12位:11111111011

尾數:第13-64位:00110011001100110011001100110011001100110011001101

總結

二進位制不能精確的表示浮點數,所以浮點數不能進行相等的比較。在涉及到金額計算的時候,建議使用BigDecimal,防止由於精度丟失帶來的BUG。