Bug Rounding Floats? (9.245 * 100).round => 924? S/B 925!

D

ddoherty03

All,

Would someone try the below unit test and explain why ruby does not
pass. It came up while I was trying to write a generalized rounding
method for floats that takes the number of place to round to as a
parameter. It gave wrong answers, but only on rare inputs.

For example, (9.245 * 100).round should be 925, but my ruby gives 924.

=================================
#! /usr/bin/env ruby
#
require 'test/unit'

class TestFloatRounding < Test::Unit::TestCase
def test_round
assert_equal(925, 924.5.round, "Rounding Error: 924.5.round")
assert_equal(9.25, (9.245 * 10.0**2).round / 10.0**2, "Rounding
Error: (9.245 * 10.0**2).round / 10.0**2")
assert_equal(925, (9.245 * 10.0**2).round, "Rounding Error:(9.245
* 10.0**2).round")
assert_equal(924.5, 9.245 * 10.0**2, "Rounding Error: 9.245 *
10.0**2")
assert_equal(925, 924.5.round, "Rounding Error: 924.5.round")
assert_equal(924.5, 9.245 * 10 * 10, "Rounding Error: 9.245 * 10 *
10")
assert_equal(925, (9.245 * 10 * 10).round, "Rounding Error: (9.245
* 10 * 10).round")
assert_equal(925.0, 9.245 * 10 * 10 + 0.5, "Rounding Error: 9.245
* 10 * 10 + 0.5")
assert_equal(925, (9.245 * 10 * 10 + 0.5).floor, "Rounding Error:
(9.245 * 10 * 10 + 0.5).floor")
end
end
===================================
 
T

Thomas Preymesser

D

ddoherty03

A workaround, convert the expression to a string and back to a number:

    num = Float("%.1f" % (9.245 * 100)).round

    puts "yippee" if num == 925

Glenn,

Thanks for the explanation. If I could pick your brain for a second
on how to generalize your workaround, I would greatly appreciate it.

Here is how I tried to implement the "nround" method.

######################################
class Float
def nround(n = 0)
(self * 10.0 ** n).round / 10.0 ** n
end
end
######################################

My issue is getting the workaround to deal with the parameter n
properly.

Regards,
 
D

ddoherty03

At 2009-07-22 03:22PM, "ddoherty03" wrote:







Taking Bil Kleb's advice,

    require 'bigdecimal'
    require 'bigdecimal/util'

    class Float
      def nround(n=0)
        (self.to_d * (10.0**n).to_d).round.to_f / 10.0**n
      end
    end

    p 9.245.nround(2)  # => 9.25

Bil & Glenn & Thomas,

Thanks. Performance is not a problem, so this works for me.

Much appreciated.
 

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,769
Messages
2,569,582
Members
45,067
Latest member
HunterTere

Latest Threads

Top