いくつかの実験の後、私はそれを理解しました。これは、丸めと切り捨ての問題です。Python はデフォルトでROUND_HALF_EVEN
丸めを使用しますが、PHP は指定された精度で単純に切り捨てます。Python のデフォルトの精度は 28 ですが、PHP では 26 を使用しています。
In [57]: import decimal
In [58]: decimal.getcontext()
Out[58]: Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, capitals=1, flags=[], traps=[InvalidOperation, Overflow, DivisionByZero])
Python に PHP の切り捨ての動作を模倣させたい場合は、rounding
プロパティを変更するだけです。
In [1]: import decimal
In [2]: decimal.getcontext().rounding = decimal.ROUND_DOWN
In [3]: decimal.getcontext().prec = 28
In [4]: a = decimal.Decimal('15.80') / decimal.Decimal('483.49870000')
In [5]: b = a * decimal.Decimal('483.49870000')
In [6]: print(b)
15.79999999999999999999999999
PHP を Python のデフォルトのように動作させるのは、少しトリッキーです。Python のように「半分を偶数」に丸める、除算と乗算用のカスタム関数を作成する必要があります。
function bcdiv_round($first, $second, $scale = 0, $round=PHP_ROUND_HALF_EVEN)
{
return (string) round(bcdiv($first, $second, $scale+1), $scale, $round);
}
function bcmul_round($first, $second, $scale = 0, $round=PHP_ROUND_HALF_EVEN)
{
$rounded = round(bcmul($first, $second, $scale+1), $scale, $round);
return (string) bcmul('1.0', $rounded, $scale);
}
ここにデモンストレーションがあります:
php > $a = bcdiv_round('15.80', '483.49870000', 28);
php > $b = bcmul_round($a, '483.49870000', 28);
php > var_dump($b);
string(5) "15.80"