I have a small repository of utility code that almost all of my Ruby projects require because I find them so beneficial to what I do. One such function is a quick precision hack for the Float class. Here’s the code:
class Float
def prec(x)
sprintf("%.0" + x.to_i.to_s + "f", self).to_f
end
end
This is nice, because it allows you to quickly round a float to a certain decimal value without having to resort to much trickery.
irb> i = 100.0 / 9.4 => 10.6382978723404 irb> i.prec(2) => 10.64
It did get me thinking though: is there a smarter way of implementing this method?
We can get rid of the sprintf and just use the % method.
class Float
def prec(x)
(("%.0" + x.to_i.to_s + "f") % self).to_f
end
end
It still seems to me like that code could be simplified even further. Do any of you have any ideas how to make it any more compact?

class Float
def prec(x)
("%.0#{x.to_i}f" % self).to_f
end
end
Looks a little less noisy to me.
James Edward Gray II
I'll second James, as that is exactly what I was going to post.
What about:
class Float
def prec(x)
(self * 10**x).to_i / (10**x).to_f
end
end
An advantage (I think) of Jonas' solution is it allows rounding on the other side of the decimal when x is negative.
1234.567.prec(-2) #=>1200.0
Also why not put prec into Numeric instead of Float?
Question: On Caleb's, James' and Ryan's solutions, why are we calling to_i on x? Doesn't x have to be an integer anyway for prec to work properly? Thanks in advance for explaining.
34 characters: (self * 10**x).to_i / (10**x).to_f
29 characters: ("%.0#{x.to_i}f" % self).to_f
in the spirit of a good game of golf, my stab at it:
19 characters: to_s[/.*\..{#{x}}/]
can't you leave off the final .to_f since coercion should take care of any type discrepancy?
to_s[/.*\..{#{x}}/]
19 characters! Ahh... line noise in ruby ;D
Hi Brian,
Our use of to_i is "Duck Typing" at work. If whatever is passed in can respond to to_i, we will have an integer. So whether the parameter is a String, a Fixnum, a Float or anything else that responds to to_i, it can be used. If it cannot be converted, an error will be thrown.
I have been using these three methods:
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
I wish the round, floor, and ceil methods allowed an optional precision argument.
This should work:
class Float
def prec( x )
sprintf( "%.*f", x, self ).to_f
end
end
Which is about as simple as I'd want it to be; any less would be obfuscatory.
(Unless maybe Ruby's printf is dumbed down compared to the one I know from C and Perl; I wouldn't know.)