Rounding float in ruby via .round

M

Marc Heiler

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?
 
P

Phillip Gawlowski

.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?
 
P

Phrogz


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
 
P

Phrogz

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

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
 
P

Phrogz

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

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
 
C

Colin Bartlett

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)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,250
Latest member
Charlesreero

Latest Threads

Top