Rounding float in ruby via .round

.round does not want arguments. Is there a reason why not?

Ok, we can easily have workarounds by extending class Float. Or using
another strategy.

http://www.hans-eric.com/code-samples/ruby-floating-point-round-off/

But it made me actually wonder - is there a reason why .round does not
want any arguments?

My brain would easily tell me that I would expect

2.29801801942891420890142890124.round(3)

to become 2.298

Is this not possible because it would become a different object?

On 02.01.2010 02:43, Marc H. wrote:

.round does not want arguments. Is there a reason why not?

Hmmm…

irb(main):001:0> RUBY_VERSION
=> “1.9.1”
irb(main):002:0> 3.14567534.round
=> 3
irb(main):003:0> 3.14567534.round 3
=> 3.146
irb(main):004:0> 3.14567534.class
=> Float

Which Ruby are you on?

On Jan 1, 9:13 pm, Phillip G. [email protected] wrote:

Which Ruby are you on?

<= 1.8.7

pharrington wrote:

On Jan 1, 9:13�pm, Phillip G. [email protected] wrote:

Which Ruby are you on?

<= 1.8.7

It shouldn’t be too hard to write that behavior into 1.8.7…

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On Jan 1, 7:22 pm, pharrington [email protected] wrote:

On Jan 1, 9:13 pm, Phillip G. [email protected] wrote:

Which Ruby are you on?

<= 1.8.7

You could do (untested on 1.8):

if Float.instance_method(:round).arity == 0
class Float
alias_method :_orig_round, :round
def round( decimals=0 )
factor = 10**decimals
(self*factor)._orig_round / factor
end
end
end

Even gives you rounding to ‘negative’ decimal places, as in 1.9

On Jan 1, 9:32 pm, Phrogz [email protected] wrote:

end
Bah, should have tested. Of course the original round returns a
fixnum, so dividing by the factor at that point really doesn’t do what
I had intended.

Here are a few alternatives. Poke fun at them and/or benchmark as you
see fit:

if Float.instance_method(:round).arity == 0
class Float
alias_method :_orig_round, :round
def round( decimals=0 )
factor = 10.0**decimals
(self*factor)._orig_round / factor
end
end
end

if Float.instance_method(:round).arity == 0
class Float
alias_method :_orig_round, :round
def round( decimals=0 )
factor = 10**decimals
(self*factor)._orig_round.to_f / factor
end
end
end

if Float.instance_method(:round).arity == 0
class Float
alias_method :_orig_round, :round
def round( decimals=0 )
factor = 10**decimals
(self*factor)._orig_round / factor.to_f
end
end
end

On Jan 1, 9:32 pm, Phrogz [email protected] wrote:

if Float.instance_method(:round).arity == 0
class Float
alias_method :_orig_round, :round
def round( decimals=0 )
factor = 10**decimals
(self*factor)._orig_round / factor
end
end
end

Even gives you rounding to ‘negative’ decimal places, as in 1.9

Note that this gives you a Float as the result, which you may need to
use sprintf to display as desired. If you want something like
JavaScript’s toFixed(), returning a string certain to be displaying
the precision you wanted, you might instead do (also untested):

class Numeric
def round_to_str( decimals=0 )
if decimals >= 0
“%.#{decimals}f” % self
else
factor = 10**-decimals
((self/factor).round * factor).to_s
end
end
end

On Sat, Jan 2, 2010 at 2:13 AM, Phillip G. [email protected]
wrote:

Hmmm…
irb(main):001:0> RUBY_VERSION #=> “1.9.1”
irb(main):002:0> 3.14567534.round #=> 3
irb(main):003:0> 3.14567534.round 3 #=> 3.146

I didn’t know 1.9 had extended Float#round. That’s useful. Thank you
for the information.

But I’m not sure that Float#round should be allowed to have
non-integer arguments:

IRB Ruby 1.9.1

n = 9876.54321
f = 1.75
r = Rational(7, 4) #=> (7/4)
c = Complex(f, 0) #=> (1.75+0i)
ci = Complex(f, 2) #=> (1.75+2i)
n.round #=> 9877
n.round 0 #=> 9877
n.round -1 #=> 9880
n.round 1 #=> 9876.5
n.round f #=> 9876.5
n.round r #=> 9876.5
n.round c #=> 9876.5
n.round ci # RangeError: can’t convert 1.75+2i into Integer

it’s nice that Integer#round is consistent with Float#round

i = 9876
i.round #=> 9876
i.round 0 #=> 9876
i.round -1 #=> 9880
i.round 1 #=> 9876.0

Rational#round: an opportunity for someone?

r = 9876 + Rational( 54321, 100000 ) #=> (987654321/100000)
r.to_f #=> 9876.54321
r.round #=> 9877
r.round 1 # ArgumentError: wrong number of arguments(1 for 0)