3

%.2n の形式で money_format を使用していますが、奇妙な結果が得られます。

サンプルコードをまとめたので、他の人が自分でテストすることができます.

<?php
    setlocale(LC_MONETARY, 'en_US');
    $deal = array(
        array(
            'amt' => 1350,
            'rate' => .75,
            'lod' => 47
        ),
        array(
            'amt' => 990,
            'rate' => .75,
            'lod' => 27
        ),
        array(
            'amt' => 4180,
            'rate' => .75,
            'lod' => 65
        ),
        array(
            'amt' => 2370,
            'rate' => .75,
            'lod' => 26
        )
    );
    foreach ($deal as $value) {
        $fee = (($value['amt'] / 1000) * $value['rate']) * $value['lod'];
        var_dump($fee);
        echo '<br />money_format: ', money_format('%.2n', $fee), '<br />number_format: ', number_format($fee, 2), '<br /><br />';
    }

出力:

float(47.5875)
money_format: $47.59
number_format: 47.59

float(20.0475)
money_format: $20.05
number_format: 20.05

float(203.775)
money_format: $203.77
number_format: 203.78

float(46.215)
money_format: $46.22
number_format: 46.22

3 番目の結果では、203.775 が 203.78 ドルではなく 203.77 ドルとして表示されます。

money_format の理解に欠けているものはありますか?

phpfiddle リンク: http://phpfiddle.io/fiddle/1909516587

4

2 に答える 2

5

これはよくある問題ですfloating point math operations

混乱の原因は、PHP のデフォルトの精度が低すぎる設定であり、var_dump.

ソース: http://php.net/manual/en/language.types.float.php

実際の数値を表示するには、より高い精度を設定するか、 を使用して精度を定義する必要があります。printfこれにより、 からの float 値がより多く表示され$feeます。

ini_set('precision',32);
var_dump($fee);
//or
printf("%01.32f", $fee);

精度の例: https://3v4l.org/ue0Th

float(47.587500000000005684341886080801)
money_format: 47.59
number_format: 47.59

float(20.04749999999999943156581139192)
money_format: 20.05
number_format: 20.05

float(203.77499999999997726263245567679)
money_format: 203.77
number_format: 203.78

float(46.215000000000003410605131648481)
money_format: 46.22
number_format: 46.22

number_formatその結果、丸めが正しくないことがわかります。同じ 10 進数値を指定すると、切り上げられた数値とそうでない数値が得られます: https://3v4l.org/pgKDs

echo number_format(23.77499999999997, 2); //returns 23.78
echo number_format(2.77499999999997, 2); //returns 2.77

原則として、精度が関係する場合は浮動小数点演算を使用せず、可能な限り低い金種 (お金の意味で 1 セント) を優先するか、bcmath 関数に依存し、乗数を使用して小数の値を取得するようにしてください。 http://php.net/manual/en/book.bc.php


bcmath を使用するように計算を変更すると、 と の両方の問題が解決されmoney_formatますnumber_format

BC 数学の例: https://3v4l.org/JEZds

bcscale(4);
foreach ($deal as $value) {
    $fee = (float) bcmul(bcmul(bcdiv($value['amt'], 1000), $value['rate']), $value['lod']);
    echo 'money_format: ' . money_format('%.2n', $fee) . PHP_EOL;
    echo 'number_format: ' . number_format($fee, 2) . PHP_EOL . PHP_EOL;
}

結果:

string(7) "47.5875"
money_format: 47.59
number_format: 47.59

string(7) "20.0475"
money_format: 20.05
number_format: 20.05

string(8) "203.7750"
money_format: 203.78
number_format: 203.78

string(7) "46.2150"
money_format: 46.22
number_format: 46.22
于 2014-07-18T17:10:04.220 に答える