<?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 之間的數?
除不盡吧?無理數吧?對了,這就是浮點數不是剛剛好等於一個十進制浮點數的原因