Ruby: Rounding Float in Ruby

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



Leave a reply



Submit