I'm using Ruby 2.3.1, and here's what I want to be able to do:
1.33333333.ceil(2) -> 1.34
1.33333333.floor(3) -> 1.333
The Float#round
method allows me to round, but I need to be able to specify if I want to round up or down, similar to the #ceil
and #floor
methods, but with a parameter to specify how many decimal places to keep.
In Ruby 2.4+, the Float#float
& Float#ceil
methods take a ndigits
argument:
1.33333333.ceil(2) -> 1.34
1.33333333.floor(3) -> 1.333
However, check out this behavior with those STD lib methods:
# In Ruby 2.4.2:
0.07.ceil(2) -> 0.08
1.1.ceil(2) -> 1.11
Not OK in my book.
For older Ruby versions or if you want to get better results than the STB lib gives, you will need to write your own methods. There are a few different blog posts out there, and I'll explain why they're not consistently correct later, but here are some methods that should work correctly every time:
require 'bigdecimal'
class Float
def ceil2(exp = 0)
BigDecimal(self.to_s).ceil(exp).to_f
end
def floor2(exp = 0)
BigDecimal(self.to_s).floor(exp).to_f
end
end
Now for more on why the following are incorrect:
def ceil_to(x)
(self * 10**x).ceil.to_f / 10**x
end
def floor_to(x)
(self * 10**x).floor.to_f / 10**x
end
# These methods also produce bad results for the examples shown above
0.07.ceil(2) -> 0.08
1.1.ceil(2) -> 1.11
I won't go into the details about what is happening (you can find that here or here), but floating point arithmetic can be messy and rounding errors do occur.