js或者php浮點數運算產生多位小數的理解


<?php
    $f = 0.58;
    var_dump(intval($f * 100)); //為啥輸出57
?>

 

 首先我們要知道浮點數的表示(IEEE 754):

浮點數, 以64位的長度(雙精度)為例, 會采用1位符號位(E), 11指數位(Q), 52位尾數(M)表示(一共64位).

符號位:最高位表示數據的正負,0表示正數,1表示負數。

指數位:表示數據以2為底的冪,指數采用偏移碼表示

尾數:表示數據小數點后的有效數字.

這里的關鍵點就在於, 小數在二進制的表示, 關於小數如何用二進制表示, 大家可以百度一下, 我這里就不再贅述, 我們關鍵的要了解, 0.58 對於二進制表示來說, 是無限長的值(下面的數字省掉了隱含的1)..

0.58的二進制表示基本上(52位)是: 0010100011110101110000101000111101011100001010001111
0.57的二進制表示基本上(52位)是: 0010001111010111000010100011110101110000101000111101

而兩者的二進制, 如果只是通過這52位計算的話,分別是:

0.58 -> 0.57999999999999996
0.57 -> 0.56999999999999995

至於0.58 * 100的具體浮點數乘法, 我們不考慮那么細, 有興趣的可以看(Floating point), 我們就模糊的以心算來看… 0.58 * 100 = 57.999999999

那你intval一下, 自然就是57了….

可見, 這個問題的關鍵點就是: “你看似有窮的小數, 在計算機的二進制表示里卻是無窮的

 

另外舉例輔助理解:

十進制數字 8,用二進制表示為 1000
可以理解為 1*2^3+0*2^2+0*2^1+0*2^0 = 8

那么小數部分怎么表示?
十進制數字 0.5,用二進制表示為 0.1
可以理解為 0*2^0+1*(2^-1) = 0.5

十進制數字 0.25,用二進制表示為 0.01
可以理解為 0*2^0+0*(2^-1)+1*(2^-2) = 0.25

十進制數字 0.75,用二進制表示為 0.11
可以理解為 0*2^0+1*(2^-1)+1*(2^-2) = 0.75

好了,問題來了 怎么表示一個 介於 0.25~0.5 之間的數?
除不盡吧?無理數吧?對了,這就是浮點數不是剛剛好等於一個十進制浮點數的原因


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM