ItIron2021
Javascript
前兩天我們把重點放在scope以及變數的宣告與賦值上,今天我們換個口味,來看一個看似簡單卻極度常見的面試題目,一起來了解javascript一些奇怪的部份吧! 老樣子,若你一看題目就知道今天的重點,你可以直接下拉到最後的結論:D
請問下方的程式碼會有什麼輸出結果?
let result = (0.1 + 0.2) === 0.3
console.log(result)
老樣子來個防雷圖,思考結束後再往下滑吧!
同樣也是個經典的面試題目,對於電腦如何處理數字的人也許已經隱隱感覺到問題在哪了,最後的輸出結果為一個赤裸裸的false
false
我懂你的心情,且讓我一步步的解釋。根本的原因其實有些許複雜,有興趣的可以自行用文末的關鍵字自行搜索甚至直接google此問題。簡單來說Javascript遵循IEEE-754標準,以64位固定長度來表示一個數字,運算時則會根據該規範先轉為二進位後再做運算,最終在這樣轉換過程中造成一些精度上的流失,讓這樣的結果出現在我們眼前。(再次強調,這只是最最最基本的說明,有興趣深入了解的請自行google,這並不是本篇文章的重點:D)
現在你知道大概的原因了,接著你很可能就被問到該如何解決! 好問題,一般來說有以下的手段。
我真的不是在講幹話,但實務上最佳的解法就是去使用已經經過多人測試過的套件,常見的選擇有math.js、big.js等,尤其在金融相關的處理上是容不得誤差的,與其自己手刻一個可能有問題的function,用現成的輪子多半是比較合理的選擇。
是的,就是那個忍術
有深入了解實際原因時就會發現這類的情況大多會發生在小數的運算上,既然如此我先把它變成整數再運算不就好了嗎? 以題目的例子來說就是這樣
const computedResult = (0.1 * 10 + 0.2 * 10) / 10
console.log(computedResult === 0.3) // true
另外還有個比較少見的方法也能解決這樣的問題,我們知道這樣的問題是來自精度的誤差,那藉由明確定義數字精度也能解決部份的情境,同樣以題目的例子來看
const computedResult = parseFloat((0.1 + 0.2).toPrecision(12))
console.log(computedResult === 0.3) // true
toPrecision函數需要傳入一個精度做為參數並回傳處理後的字串,精度12則可以處理大多數的精度誤差問題。
浮點數陷阱
本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!