moneyphp / money

PHP implementation of Fowler's Money pattern.
http://moneyphp.org
MIT License
4.63k stars 441 forks source link

Wrong calculate? #587

Closed anhskohbo closed 4 years ago

anhskohbo commented 4 years ago

Hello, I can't make this work correctly when working with cents.

<?php

dump(10.5/100*20);
dump(Money::USD('1050')->divide(100)->multiply(20)->getAmount());

// 2.1
// "220" ~ 2.2

I have try to pass $roundingMode but still not correct.

UlrichEckhardt commented 4 years ago

1050 / 100 ~= 11, 11 * 20 = 220. Seems legit. Just swap multiplication and division to avoid the loss of precision in the first step.

anhskohbo commented 4 years ago

I tried, the default rounding mode is rounded up at the first step divide(100).

<?php

$money = Money::USD('1050');
$onePercent = $money->divide(100); // amount value is 11.

Seem no way to correct that. I will let customers will be lost one cent in that case :)

UlrichEckhardt commented 4 years ago

You only need to multiply first:

1050 * 20 = 21000
21000 / 100 = 210
sagikazarmark commented 4 years ago

As @UlrichEckhardt said, you lose precision between the two steps, because it's not preserved between calculations. After dividing the initial value, you get back a money object, not an intermediary result.

You either have to switch the order of operations, or really just merge them:

Money::USD('1050')->multiply(20/100)