如何改进此算法?

mer*_*cam 0 php currency

我想要实现的是获取美元货币金额,并将其分解为使用每种类型中最少的金额来计算每个账单和硬币的数量.

我匆匆写了这篇文章,它有效,但我觉得它可以改进.此外,我不得不围绕其余部分,因为我得到一个奇怪的结果一旦它得到像(0.13 - (1*0.1)而不是0.3它会出现0.299999995

下面的代码确实有效.

function moneybreak ($amount, $sizebill) {
    // get units of sizecurrency
    $numbills = floor($amount / $sizebill);
    $remainder = $amount - ($numbills * $sizebill);
    $remainder = round($remainder, 2);
    $ret['bills'] = $numbills;
    $ret['remain'] = $remainder;
    return $ret;
}

$amount = 1999.99;
$money = array();
$tmoney = moneybreak($amount, 500);
$money['fivehundred']   = ($tmoney['bills'] > 0) ? $tmoney['bills'] : 0.00;
$tmoney = moneybreak($tmoney['remain'], 100);
$money['onehundred']        = ($tmoney['bills'] > 0) ? $tmoney['bills'] : 0.00;
$tmoney = moneybreak($tmoney['remain'], 20);
$money['twenty']            = ($tmoney['bills'] > 0) ? $tmoney['bills'] : 0.00;
$tmoney = moneybreak($tmoney['remain'], 10);
$money['ten']               = ($tmoney['bills'] > 0) ? $tmoney['bills'] : 0.00;
$tmoney = moneybreak($tmoney['remain'], 5);
$money['five']              = ($tmoney['bills'] > 0) ? $tmoney['bills'] : 0.00;
$tmoney = moneybreak($tmoney['remain'], 1);
$money['one']               = ($tmoney['bills'] > 0) ? $tmoney['bills'] : 0.00;
$tmoney = moneybreak($tmoney['remain'], 0.25);
$money['quarter']           = ($tmoney['bills'] > 0) ? $tmoney['bills'] : 0.00;
$tmoney = moneybreak($tmoney['remain'], 0.1);
$money['dime']              = ($tmoney['bills'] > 0) ? $tmoney['bills'] : 0.00;
$tmoney = moneybreak($tmoney['remain'], 0.05);
$money['nickle']            = ($tmoney['bills'] > 0) ? $tmoney['bills'] : 0.00;
$tmoney = moneybreak($tmoney['remain'], 0.01);
$money['penny']         = ($tmoney['bills'] > 0) ? $tmoney['bills'] : 0.00;
Run Code Online (Sandbox Code Playgroud)

zne*_*eak 5

您的问题是一个完美的例子,说明为什么不应该使用浮点算术来表示货币.

首先,你需要避免浮点数,就像你欠他们很多钱(尽管实际上可能相反).为此,我们将用美分而不是美元进行计算.您可能需要的任何金额都需要乘以100.

然后,您可以通过将要使用的所有货币单位($ 100,$ 50,$ 20,...)列入数组,然后按降序对其进行排序,以便最大的数据首先出现.

<?php

// money units, in cents
// (reflecting common Canadian currency)
$units = array(10000, 5000, 2000, 1000, 500, 200, 100, 25, 10, 5, 1);
function moneyBreak($amount, $units)
{
    // ensure the array is sorted in descending order
    rsort($units);
    $itemsOfEach = array();
    // loop through all the money units
    foreach ($units as $unit)
    {
        // you'll try to use this money unit for the largest possible
        // amount of money
        $itemsOfEach[$unit] = intval($amount / $unit);
        // and once you're done, you'll continue with the remainder
        $amount %= $unit;
    }
    return $itemsOfEach;
}

?>
Run Code Online (Sandbox Code Playgroud)

这是一个例子:

$amount = 32347; // $323.47
$result = moneyBreak($amount, $units);
print_r($result);
/* prints this:
Array
(
    [10000] => 3
    [5000] => 0
    [2000] => 1
    [1000] => 0
    [500] => 0
    [200] => 1
    [100] => 1
    [25] => 1
    [10] => 2
    [5] => 0
    [1] => 2
)
*/
Run Code Online (Sandbox Code Playgroud)