Ruby: Rounding float in Ruby
When displaying, you can use (for example)
>> '%.2f' % 2.3465
=> "2.35"
If you want to store it rounded, you can use
>> (2.3465*100).round / 100.0
=> 2.35
Ruby round Float up or down to specific decimal significant figure
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.
Round a ruby float up or down to the nearest 0.05
Check this link out, I think it's what you need.
Ruby rounding
class Float
def round_to(x)
(self * 10**x).round.to_f / 10**x
end
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
end
How do you round a float to 2 decimal places in JRuby?
Float#round can take a parameter in Ruby 1.9, not in Ruby 1.8. JRuby defaults to 1.8, but it is capable of running in 1.9 mode.
Round float to the nearest quarter in Ruby
(1.27 * 4).round / 4.0
#=> 1.25
If you're going to use it often, it would make perfect sense to monkey patch the Float
class, to make the usage simpler:
class Float
def round_to_quarter
(self * 4).round / 4.0
end
end
1.27.round_to_quarter
#=> 1.25
1.52.round_to_quarter
#=> 1.5
1.80.round_to_quarter
#=> 1.75
1.88.round_to_quarter
#=> 2.0
How do I rounding of zeros in Ruby
What you seek is not exactly rounding but formatting.
You can select your float formatting like this:
p "%.2f" % 12121.0000
where the %.2f
part means "show 2 decimal points"
Float number format without rounding in ruby
Unfortunately, unlike Float#round
, Float#floor
does not accept an amount of digits. The below code implements the desired behaviour.
def floor_float input, digits = 3
input.divmod(10 ** -digits).first / (10 ** digits).to_f
end
This might be used as monkey patch:
class Float
def floor_ext digits = 3
self.divmod(10 ** -digits).first / (10 ** digits).to_f
end
end
22.0098.floor_ext
#⇒ 22.009
Probably more succinct variant as suggested by @Stefan:
class Float
def floor_ext digits = 3
div(10 ** -digits).fdiv(10 ** digits)
end
end
22.0098.floor_ext
#⇒ 22.009
Or, one might deal with strings explicitly:
i, f = 22.0098.to_s.split('.')
#⇒ [ "22", "0098" ]
[i, f[0..2]].join('.')
#⇒ "22.009"
Ruby Float#round behaviour change after update
The behaviour you're describing sounds like https://bugs.ruby-lang.org/issues/13138, which was considered a bugfix and backported to 2.3.5. (I haven't confirmed which 2.4.x it was backported to, if any, but it was in trunk before 2.5.0.)
As you surmised, it is a precision issue. 1.34875's float representation is slightly less than 1.34875, so 2.3.3 does the overly-technically-correct thing and rounds down; newer versions recognise that rounding up is more consistent given that the float actually represents a range of values [including 1.34875].
A way to round Floats down
Based on answer from @kimmmo this should be a little more efficient:
class Float
def round_down n=0
s = self.to_s
l = s.index('.') + 1 + n
s.length <= l ? self : s[0,l].to_f
end
end
1.9991.round_down(3)
=> 1.999
1.9991.round_down(2)
=> 1.99
1.9991.round_down(0)
=> 1.0
1.9991.round_down(5)
=> 1.9991
or based on answer from @steenslag, probably yet more efficient as there is no string conversion:
class Float
def round_down n=0
n < 1 ? self.to_i.to_f : (self - 0.5 / 10**n).round(n)
end
end
Related Topics
How to Push to Faye Server from Rails Controller
Escape Single Quote in Xpath with Nokogiri
Why Can't I Use an Integer as a Key Using the New Ruby 1.9.2 Hash Syntax
Error: Failed to Build Gem Native Extension (Ruby Extconf.Rb): MAC Osx
Getting Uninitialized Constant Error When Trying to Run Tests
Rvm Does Not Install Ruby 1.9.2 on Snow Leopard: 'Error Running 'Make '
How to Improve Jruby Load Time
Why Does Array.Each Behavior Depend on Array.New Syntax
Optional Arguments with Default Value in Ruby
Ruby Array to JSON and Rails JSON Rendering
Bundle Install Issue with Libv8 and Rails
Building Ruby with Rbenv and Ruby-Build Fails with Undefined Symbol: Sslv2_Method
How to Change Column Type in Heroku
How to Handle a Thread Issue in Zeromq + Ruby