2008-10-11 43 views
4

我有一個小型財務應用程序,PHP作爲前端,MySQL作爲後端。我有古老的偏見,我在MySQL中存儲貨幣價值爲整數美分。我的HTML表單允許輸入美元值,如「156.64」,我使用PHP將其轉換爲美分,然後將美分存儲在數據庫中。PHP的錢字符串轉換爲整數錯誤

我有一個函數可以清除表單中的美元值,並將其轉換爲美分。我去掉前導文本,去掉尾隨文本,乘以100並轉換爲整數。這最後一步是

$cents = (integer) ($dollars * 100);

這幾乎一切工作正常,除了像「156.64」,這始終轉換爲15663美分極少數的值。它爲什麼這樣做?

如果我這樣做:

$cents = (integer) ($dollars * 100 + 0.5);

那麼它始終工作。爲什麼我需要添加該舍入值?

此外,我對存儲金額的整數而不是浮點值的偏見是不再需要的嗎?現代浮動計算會產生足夠的圓整準確的貨幣值,以保持100%準確的會計?

回答

4

如果您需要精確度,您應該使用MySQL中的DECIMAL數據類型存儲您的貨幣值。

2

你對浮標的「偏見」永遠不會被克服 - 這是他們工作方式的基礎。沒有詳細說明,他們根據2的冪數來存儲一個數字,並且由於並非所有的十進制數都可以用這種方式表示,所以它並不總是工作。您唯一可靠的解決方案是將數字存儲爲數字序列和小數點位置(按照上述的DECIMAL類型)。

我不是100%的PHP,但它有可能是乘法將整數轉換爲浮點數,因此正確地引入了您試圖避免的問題?

2

貨幣/貨幣值永遠不應該作爲浮動數據存儲在數據庫中(或在程序中使用)。

您的整數方法很好,因爲在可用的情況下使用的是DECIMALNUMERICMONEY類型。

您的問題是由於美元被視爲浮動而導致的,而PHP沒有更好的類型來處理資金。根據何時分配$美元,它可以被當作字符串或浮點數處理,但如果它看起來像浮點數,它仍然是* 100操作的字符串,它肯定會轉換爲浮點數。

你可能會更好地將字符串解析爲整數「money」值(使用正則表達式),而不是依賴PHP正在執行的隱式轉換。

2

鑄造不是round(),因爲它是最接近的,它的truncates在十進制:(int)3.99收益率3(int)-3.99,收率-3

由於浮點運算常常會導致錯誤(並且可能不是您想要的方向),因此如果要進行可靠舍入,請使用round()

+1

錯誤。投擲輪。看到我的回覆 – 2010-01-14 12:32:20

2

您發佈的代碼首先進行乘法運算,在將值轉換爲整數之前強制引入錯誤的浮點計算。相反,您應該完全通過顛倒順序來避免浮點運算。首先轉換爲整數值,然後執行算術運算。

假設上面的代碼已經驗證和格式化輸入,試試這個:

list($bills, $pennies) = explode('.', $dollars); 
$cents = 100 * $bills + $pennies; 

您對浮點值來表示錢的偏見是很合理的,因爲截斷,因爲值的和基10被轉換到base-2並返回。

0

而不是使用

$ cents =(integer)($ dollars * 100);

你可能想嘗試使用:

$分= bcmul($美元,100,2);

0

如果您通過浮點運算(無雙關語)輸入貨幣,則將貨幣存儲爲整數沒有意義。如果你想從string轉換爲int,並與你的「偏見」一致,你可以簡單地使用字符串函數。

您可以使用任意精度庫除以10(它們在內部以字符串形式處理數字),例如, bcdiv()gmp_div_q(),但當然,您也可以從一開始就使用它來計算所有數學。

或者你可以使用普通字符串函數:

<?php 
// Quick ugly code not fully tested 
$input = '156.64'; 
$output = NULL; 

if(preg_match('/\d+(\.\d+)?/', $input)){ 
    $tmp = explode('.', $input); 
    switch(count($tmp)){ 
     case 1: 
      $output = $tmp[0]; 
      break; 

     case 2: 
      $output = $tmp[0] . substr($tmp[1], 0, 2); 
      break; 

     default: 
      echo "Invalid decimal\n"; 
    } 
}else{ 
    echo "Invalid number\n"; 
} 

var_dump($output); 

?> 
1

你永遠也不會儲存貨幣浮點數,因爲它總是讓你不希望的結果。

查看php BC Maths,它允許您將貨幣存儲爲字符串,然後對其執行非常高精度的算術運算。