drq231358 2015-01-19 14:00
浏览 40

PHP计算逻辑问题

Not sure if I'm being stupid here. Probably something obvious but when you've been staring at the same issue for hours on end it starts to drive you crazy.

I'm doing a few calcuations using PHP, all fairly straight forward.

I have a table called sales, say:

total, costs
424.53, 125
853.91, 125

To get the data I need...

gross = total - cost
vat   = gross - ( gross / 1.2 )
profit = gross - vat

I need to generate a report, so for each row in the sales database I need to loop over and run the above calculations to get the data I need.

If I add the sum of total and the sum of costs, and then work out the gross, vat and profit above, and round vat and profit to 2 decimal plates the values are as expected.

The problem I'm having is where I'm looping over each row and calculating gross, vat and profit. If I don't round vat and profit on each row, but round the final totals, they match the values where I add sum(total) and sum(costs).

But then in the report I generate, if I don't round vat and profit then they don't show to two decimal places, which I need.

Actual code is below, pretty sure it's more of a logic issue than code.

    $sum = 0; // Test variable
    foreach( .. as ... )
    {
        // Assigning $total and $cost

        $gross = $total - $cost;

        $data['profit'] = $gross;

        // If I round this VAT so vat shows to two decimal points, $sum becomes off by some pence.
        // If I don't round it but then round $sum after the loop, it matches the echo statement value which is the correct amount
        $vat = $this->vat( $gross );

        $data['vat'] = $vat;

        $profit = $gross - $vat;

        $data['net_profit'] = $profit;

        $sum += $profit;

        $array[] = $data;
    }

    echo "131547.82<br><br>";

    echo $sum;
    die;
  • 写回答

1条回答 默认 最新

  • doushi1929 2015-01-19 14:22
    关注

    It's an accuracy problem caused by using floats.

    When you do calculations with pure PHP you need to be careful. You may run into glitches, when comparing two floats. I would suggest to use some helper function or a currency / money object in order to work with them. It might be better to use a PHP Extension for math stuff, like the PHP Extensions BCMath, which has for instance the function bcadd(). Anyway, here are some helpers, which you might use in your calculation loop.

    /**
     * turn "string float" into "rounded float with precision 2"
     * (string) 123,19124124 = (float) 123.19
     * 
     * @param type $string
     */
    function formatNumber($string, $precision = 2)
    {
        return round((float) str_replace(',', '.', $string), $precision);
    }
    

    There is also sprintf: echo sprintf("%.2f", $a);.

    These two are based on PHP's NumberFormatter from the Intl Extension.

    // 123,19 EUR = 123.19
    function parseNumber($string_number)
    {
        $fmt = numfmt_create('de_DE', \NumberFormatter::DECIMAL);
        return numfmt_parse($fmt, $string_number);
    }
    
    // 123.19 = 123,19 EUR
    function numberFormat($value)
    {
        $f = \NumberFormatter::create("de_DE", \NumberFormatter::CURRENCY);
        return $f->formatCurrency($value, 'EUR');
    }
    

    For comparing two floats:

    /** 
     * Do not check, that the numbers are exactly the same, 
     * but check that their difference is very small!
     * A really small rounding error margin (epsilon) is expected.
     * It's an equals check within defined precision.
     */
    function compareFloats($a, $b)
    {
        return (abs(($a - $b) / $b) < 0.000001) ? true : false;
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
  • ¥15 神经网络怎么把隐含层变量融合到损失函数中?
  • ¥30 自适应 LMS 算法实现 FIR 最佳维纳滤波器matlab方案
  • ¥15 lingo18勾选global solver求解使用的算法
  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥15 Python3.5 相关代码写作
  • ¥20 测距传感器数据手册i2c
  • ¥15 RPA正常跑,cmd输入cookies跑不出来
  • ¥15 求帮我调试一下freefem代码
  • ¥15 matlab代码解决,怎么运行