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
LOL, will FIX. Thanks for flagging this!
this issue has been fixed for a while
> Money.new("100000000000000000000000000", "USD").to_s
=> "100000000000000000000000000.00"