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

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.02).round / 10.02, “Rounding
Error: (9.245 * 10.02).round / 10.02”)
assert_equal(925, (9.245 * 10.0**2).round, "Rounding Error:(9.245

  • 10.02).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
    ===================================

2009/7/22 ddoherty03 [email protected]

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

try what your term really is:

printf(“%.50f”,9.245 * 100)

-Thomas


Thomas P.
[email protected]

Mike Ditka http://www.brainyquote.com/quotes/authors/m/mike_ditka.html

“If God had wanted man to play soccer, he wouldn’t have given us arms.”

At 2009-07-22 01:37PM, “Thomas P.” wrote:

printf("%.50f",9.245 * 100)
Welcome to IEEE floating-point arithmetic. Any programming language
that uses it will be subject to the same results.

On Jul 22, 1:13 pm, Glenn J. [email protected] wrote:

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,

At 2009-07-22 02:08PM, “Glenn J.” wrote:

printf("%.50f",9.245 * 100)

Welcome to IEEE floating-point arithmetic. Any programming language
that uses it will be subject to the same results.

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

At 2009-07-22 03:22PM, “ddoherty03” wrote:

Here is how I tried to implement the “nround” method.
properly.
Taking Bil K.'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

ddoherty03 wrote:

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

If performance isn’t a problem, you could use ‘bigdecimal’:

http://ruby-doc.org/stdlib/libdoc/bigdecimal/rdoc/

See for example,

Ruby Quiz - NDiff (#46)

Regards,

On Jul 23, 9:37 am, Glenn J. [email protected] wrote:

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

p 9.245.nround(2)  # => 9.25


Glenn J.
Write a wise saying and your name will live forever. – Anonymous

Bil & Glenn & Thomas,

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

Much appreciated.