Reputation: 3455
I understand due to the inexact representation of floating points, the following code 'feels' inconsistent.
"%.1f" % 1.14 # => 1.1
"%.1f" % 1.15 # => 1.1
"%.1f" % 1.16 # => 1.2
"%.0f" % 1.4 # => 1
"%.0f" % 1.5 # => 2
"%.0f" % 1.6 # => 2
However, is there an easy way of doing consistent floating points rounding by 5? One way might be to do string manipulation explicitly. Is there an easier way or existent library?
Upvotes: 2
Views: 1642
Reputation: 16906
The function roundthis()
in this example shows how to round numbers in a controllable, consistent way. Note the small fudge value. Try running this example without the fudge to see what happens.
def roundthis(x, m)
return (x/m+0.50001).floor*m
end
for x in [1.14, 1.15, 1.16]
print "#{x} #{roundthis(x, 0.1)} \n"
end
for x in [1.4, 1.5, 1.6]
print "#{x} #{roundthis(x, 1.0)} \n"
end
This, put into a file named roundtest.rb and executed prints
bash> ruby roundtest.rb
1.14 1.1
1.15 1.2
1.16 1.2
1.4 1.0
1.5 2.0
1.6 2.0
Note the ease of rounding to the nearest 2, 15, 0.005, or whatever.
Upvotes: 1
Reputation: 20000
If you want decimal precision, use BigDecimal instead of floats.
Edit: You will have to manually round the number to the desired length before passing it to %
, otherwise it gets converted to a normal float before being rounded.
"%.1f" % BigDecimal('1.15').round(1) => "1.2"
"%.0f" % BigDecimal('1.5').round(0) => "2"
Upvotes: 5
Reputation: 132177
Just add a tiny pertubation, to ensure things that are just under 0.5 in floating-point become just over.
For example,
x = 1.15
"%.1f" % (1.000001*x) # include correction for imprecise floating-point.
this will be enough to deal with the formatting problems, while very unlikely to cause a relevant error.
also: an obvious follow-on to my earlier question here, which is fine, but included for completeness.
Upvotes: 2
Reputation: 29442
Multiply by 100, then round, then divide by 100:
(1.15 * 100).round / 100.0 # => 1.15
It's not exactly elegant, but it avoids using strings.
Upvotes: 0