Shopify/money

Money#to_s converts number to float before formatting

dylanahsmith opened this issue · 2 comments

irb> Money.new("100000000000000000000000000").to_s
=> "100000000000000004764729344.00"

This is because sprintf("%.2f", value) or sprintf("%.#{currency.minor_units}f", value) is being used to format the string the string, which is converting the number to a float before formatting the string, which loses precision.

We could instead use BigDecimal#to_s to format the string, although it doesn't support specifying the number of digits after the decimal to output.

Floats are dangerous for really large numbers or if no rounding is happening. sprintf will automatically round so even though

129.95 * 100 => 12994.999999999998

we still get the correct value

sprintf("%.2f", 129.95 * 100) => "12995.00"

We still have the issue of really big numbers (greater than 15 digits). For money that's somewhat less of a concern since the max 15 digit number is

nine hundred ninety-nine trillion, nine hundred ninety-nine billion, nine hundred ninety-nine million, nine hundred ninety-nine thousand, nine hundred ninety-nine

https://www.calculatorsoup.com/calculators/conversions/numberstowords.php

So somewhat unlikely... but then again
image

LOL, will FIX. Thanks for flagging this!

this issue has been fixed for a while

> Money.new("100000000000000000000000000", "USD").to_s
=> "100000000000000000000000000.00"