2013-11-25 23 views
3

我正在計算某些東西的費用(貨幣),而PHP在數量應該爲0.00時表現得很奇怪。它以浮點數形式給出最終結果,而不是0。PHP奇怪地減去數字 - 返回長浮動值

在我的數據庫中,我有如下表

id | transaction_total | charge_fees | deposit_fee | amount_to_customer | fees_minus_total_difference 

所以,當我去檢查,以確保所支付的費用+量 - 總= 0.00

(96.54 + .25 + 3.20 - 99.99) = 1.4210854715202E-14 

爲什麼結果浮動數字,而不是實際零?數字本來是更多的小數位,但我用number_format把它放到2個地方。例如,收費實際上可能是3.19987

number_format(3.19971,2,'.','') //equals 3.20 

當我將它保存在我的數據庫中時,它顯示爲3.20。當我在總計/費用檢查的計算中使用它時,結果不是零,儘管接近。

+1

http://en.wikipedia.org/wiki/Floating_point#Representable_numbers.2C_conversion_and_rounding – deceze

+1

切勿使用*貨幣價值浮動點*,除非你不介意失去少量的錢(或者獲得一些,也許)。要麼以美分計算,要麼以像bcmath這樣的任意精度庫來計算。 – deceze

+0

[PHP Math Precision]的可能重複(http://stackoverflow.com/questions/3726721/php-math-precision) – deceze

回答

4

計算機存儲號碼以二進制,所以當你試圖代表你可能會失去精度的十進制數。這就是發生在這裏的事情。

一些語言具有精確的精度類型,但不幸的是PHP不能。不過,它確實爲您提供了BC MathGMP。儘管如此,在這裏使用這些似乎是過分的。使用BC,你可以這樣做:

bcsub(bcadd(bcadd('96.54','0.25',2),'3.20',2),'99.99',2) = 0 

請注意,你必須在這裏指定小數點數(2)。

一般來說,使用浮點數和double來表示財務狀況令人不悅,但對於PHP來說,它看起來更簡單一些。我建議您只需使用round()將您的數字四捨五入到輸入的小數位數。

round(96.54 + .25 + 3.20 - 99.99,2) = 0 
+0

您需要將數字作爲字符串提供給bc函數。只要在你的源代碼中寫入'0.12345'已經使你失去了精確性。它應該是'bcadd'('1.234','5.678')'。 – deceze

+1

@deceze當然,謝謝。我更新了我的答案。 – kba

2

我建議不要使用number_format()以外的顯示字符串。改爲使用round()

你的問題是浮點數。 PHP有更精確的數學函數,你可以看看像bcadd,bcmul,bcdiv等..

http://php.net/manual/en/book.bc.php