number_to_currency rounding precision wrong
I am very curious why Ruby render decimal with precision 2 in开发者_运维知识库consistently.
For example:
helper.number_to_currency 9.995
=> "$9.99"
whilst
helper.number_to_currency 10.995
=> "$11.00"...should it be "$10.99"?
It is a floating point precision error. I will probably submit a patch to fix this because I'm using number_to_currency on my website too.
Here's what's happening in more detail:
number_to_currency
ends up just calling number_with_precision
to get the number correctly formatted. number_with_precision
immediately converts the number to a Float. Essentially, it comes down to this line in the Rails code:
# File actionpack/lib/action_view/helpers/number_helper.rb, line 280
rounded_number = BigDecimal.new((number * (10 ** precision)).to_s).round.to_f / 10 ** precision
The number you provide is multiplied by 100 before it is converted to BigDecimal. Look at this simple irb session:
irb(main):001:0> 9.995 * 100
=> 999.4999999999999
That number would obviously round down to 999, then it will be divided by 100 to give you 9.99.
The only workaround for this that I can think of for the moment is to do your own rounding before you pass in the number.
Looks like it is using "Round half to odd" rule.
So "1.5" gets rounded down to the nearest odd number (1) and 2.5 gets rounded up to the nearest odd number (3).
For a randomly distributed set of numbers to be rounded this form of rounding will consitently produce the smallest difference between the sum of unrounded numbers and the sum of rounded numbers.
精彩评论