先看兩個簡單但詭異的**:
0.1 + 0.2 > 0.3 // true
0.1 * 0.1 = 0.010000000000000002
0.1加0.2為什麼就不等於0.3暱?要回答這個問題,得先了解計算機內部是如何表示數的。
我們都知道,計算機用位來儲存及處理資料。每乙個二進位制數(二進位制串)都一一對應乙個十進位制數。
1. 計算機內部如何表示整數
這裡以十進位制數13來展示「按位計數法」如何表示整數:
十進位制值
進製按位格式
描述13
1013
1x10^1 + 3x10^0 = 10 + 3132
1101
1x2^3 + 1x2^2 + 0x2^1 + 1x2^0 = 8 + 4 + 0 + 1
2. 計算機內部如何表示小數
再看小數怎麼用按位計數法表示,以十進位制數0.625為例:
十進位制值
進製按位格式
描述0.625
100.625
6x10^-1 + 2x10^-2 + 5x10^-3 = 0.6 + 0.02 + 0.005
0.625
20.101
1x2^-1 + 0 x2^-2 + 1x2^-3 = 1/2 + 0 + 1/8
3. 如何用二進位制表示0.1
關於十進位制與二進位制間如何轉換,這裡不細說,直接給出結論:
十進位制整數轉二進位制方法:除2取餘;十進位制小數轉二進位制方法:乘2除整
十進位制0.1轉換成二進位制,乘2取整過程:
0.1 * 2 = 0.2 # 0
0.2 * 2 = 0.4 # 0
0.4 * 2 = 0.8 # 0
0.8 * 2 = 1.6 # 1
0.6 * 2 = 1.2 # 1
0.2 * 2 = 0.4 # 0
.....
從上面可以看出,0.1的二進位制格式是:0.0001100011....。這是乙個二進位制無限迴圈小數,但計算機記憶體有限,我們不能用儲存所有的小數字數。那麼在精度與記憶體間如何取捨呢?
答案是:在某個精度點直接捨棄。當然,代價就是,0.1在計算機內部根本就不是精確的0.1,而是乙個有捨入誤差的0.1。當**被編譯或解釋後,0.1已經被四捨五入成乙個與之很接近的計算機內部數字,以至於計算還沒開始,乙個很小的捨入錯誤就已經產生了。這也就是 0.1 + 0.2 不等於0.3 的原因。
有誤差的兩個數,其計算的結果,當然就很可能與我們期望的不一樣了。注意前面的這句話中的「很可能」這三個字?為啥是很可能暱?
答案是:兩個有捨入誤差的值在求和時,相互抵消了,但這種「負負得正,相互抵消」不一定是可靠的,當這兩個數字是用不同長度數字來表示的浮點數時,捨入誤差可能不會相互抵消。
又如,對於 0.1 + 0.3 ,結果其實並不是0.4,但0.4是最接近真實結果的數,比其它任何浮點數都更接近。許多語言也就直接顯示結果為0.4了,而不展示乙個浮點數的真實結果了。
另外要注意,二進位制能精確地表示位數有限且分母是2的倍數的小數,比如0.5,0.5在計算機內部就沒有捨入誤差。所以0.5 + 0.5 === 1
我們看兩個現實的場景:
不同行業,要求的精度不是線性的,我們允許(對結果無關緊要的)誤差存在。10.0001與10.001在鐵路工程師看來都是合格的。
雖然允許誤差存在,但程式設計師在使用浮點數進行計算或邏輯處理時,不注意,就可能出問題。記住,永遠不要直接比較兩個浮點的大小:
var a = 0.1
var b = 0.2
if (a + b === 0.3)
將浮點運算轉換成整數計算
整數是完全精度的,不存在捨入誤差。例如,一些關於人民幣的運算,都會以分為基本單位,計算採用分,展示再轉換成元。當然,這樣也有一些問題,會帶來額外的工作量,如果那天人民幣新增了乙個貨幣單位,對系統的擴充套件性也會有考驗。
使用bignumber進行運算
bignumber.js會在一定精度內,讓浮點數計算結果符合我們的期望。
更多例子,可以看bignumber.js官方示例。 在js中為什麼0 1 0 2不等於0 3
0.1 0.2 0.3 false原因在於在js中採用的ieee 754的雙精度標準,計算機內部儲存資料的編碼的時候,0.1在計算機內部根本就不是精確的0.1,而是乙個有捨入誤差的0.1。當 被編譯或解釋後,0.1已經被四捨五入成乙個與之很接近的計算機內部數字,以至於計算還沒開始,乙個很小的捨入錯誤...
46 為什麼 NaN 不等於自身?
nan,它是用來表示是否屬於number型別的一種狀態 是或否。而不是乙個確切的值。nan值一般會在什麼情況下出現呢?一般有兩種情況 1 乙個表示式中如果有減號 乘號 或 除號 等運算子時,js引擎會在計算之前試圖將運算子兩邊的變數轉化為number型別,如果轉化失敗,表示式將返回nan 2 直接使...
專案管理 付出為什麼不等於收穫?
有些人付出很多但收穫很少,也有些人付出很少卻獲益多多。這不符合古人所謂 天道酬勤 也不符合今人所言 能量守恆 好像無論從社會科學還是自然科學的角度,付出都應該等於收穫。為什麼我們看到的現象與此不符?那是因為我們忽略或者沒有看到其中的隱藏因素。如果用公式來表達付出與收穫之間的關係,應該是下面兩個公式 ...