js-money icon indicating copy to clipboard operation
js-money copied to clipboard

Possibly wrong result after multiplication

Open magnusjt opened this issue 7 years ago • 4 comments

Multiplying these two numbers together seems to yield the wrong result:

Money.fromDecimal(2090.50, Money.USD).multiply(Money.fromDecimal(8.61, Money.USD)).toDecimal() // = 17999.2

Should be 17999.21.

Internally I think this is what happens:

209050 * 8.61 // = 1799920.499999999.... Math.round(1799920.4999999998) // = 1799920

magnusjt avatar Oct 24 '17 11:10 magnusjt

It tests if you passed in a rounder, if not it defaults to regular old Math.Round: if (!isFunction(fn)) fn = Math.round;

If you add the rounder of your choice to the formula you should get what you want. For example: Money.fromDecimal(2090.50, Money.USD).multiply(Money.fromDecimal(8.61, Money.USD),Math.ceil).toDecimal()

Result: 17999.21

tastypackets avatar Oct 24 '17 16:10 tastypackets

The thing is, I don't want to use ceil here since every other number would also be rounded up. The issue is that 1799920.499999999.... is actually 1799920.5 in precise arithmetic, and should be round up.

magnusjt avatar Oct 24 '17 19:10 magnusjt

Hmm perhaps someone can review and or write up some code to better handle rounding after the currency decimal place. I believe MDN had some documentation on this or maybe it was stack exchange I read about it.

At the end of the day though if financial precision is important down to the fraction of a cent it may be something that should be shifted off JS and to a language that better supports decimal values.

tastypackets avatar Oct 24 '17 20:10 tastypackets

Maybe use something like https://github.com/MikeMcl/big.js ? I think you get most of the precision related stuff for free with a library like that.

Edit: And another bonus is that you get correct rounding for negative numbers.

magnusjt avatar Oct 25 '17 13:10 magnusjt