ruby 1.8.5. I’ll give it a try on 1.8.6 and let you know.
It’s not a bug. It’s the way floating point arithmetic works, and is
true for most programming languages.
Dear friends, today I have stumbled into a really weird problem. Try
typing this on irb:
14.95 * 0.6 == 8.97
Ruby says it’s false!
This happens in all languages that use floating point to represent
decimal numbers (you will get precisely the same result in C or
Javascript or Perl, for instance). Floating-point arithmetic is only
approximate, so the result does not exactly equal 8.97, even though it
is very close.
Because of this, when using floating-point arithmetic, testing for exact
equality is impractical. The best you can do is test whether the result
is within some interval (epsilon) of the expected result:
( ( 14.95 * 0.6 ) - 8.97 ).abs < 1e-6
(Here, we’ve chosen 1e-6 as our epsilon, which is arbitrary but probably
“small enough” in this case. For mathematically intensive code, you may
need to be more careful.)
Although floating-point is the default for Ruby, you do have the option
of using a different representation of numbers for which arithmetic is
exact, although it will not be as fast. One such option is the Rational
class in Ruby’s standard library, which represents numbers as fractions
rather than floating-point numbers.
You are rigth James, but you can better reponse why is a floating point
error?
Some numbers (like 0.1) cannot be represented exactly in binary with a
finite number of bits (because 0.1[base 10] =
0.0001100110011001100110011…[base 2]) and when they are represented
(as it happens with floating point representations), they lose
precision. So you must not test floating point for equality but always
rely on some tolerance and use an expression like MenTaLguY showed:
On Fri, 22 Jun 2007 04:40:29 +0900, “juan pedro meriño” [email protected] wrote:
You are rigth James, but you can better reponse why is a floating point
error?
Not all numbers can be represented by an arbitrarily small number of
digits, and floating-point numbers only have so many digits available
(for Ruby, 53 binary digits, which is about 16 decimal digits). In this
case, the computation required more than 53 bits, so the result was
approximate.
rely on some tolerance and use an expression like MenTaLguY showed:
( 14.95 * 0.6 - 8.97 ).abs < tol
where tol depends on your application.
I’m starting to remember something about that on my computer
architecture course. But it’s something so technical and I’m so used
to high level programming, that I couldn’t remember…
I’m starting to remember something about that on my computer
architecture course. But it’s something so technical and I’m so used
to high level programming, that I couldn’t remember…
I guess it goes to show that one never really escapes this stuff,
even in “high level” programming.
Does anyone know how these languages get the correct result?
matz.
A simple way to get the correct figure is to do what is used often with
currency to prevent these types of errors. If I enter ‘puts
1495.0*6.0/1000.0’ I get 8.97. The only thing necessary is to keep
track of the number of decimal points.
A simple way to get the correct figure is to do what is used often with
currency to prevent these types of errors. If I enter ‘puts
1495.0*6.0/1000.0’ I get 8.97. The only thing necessary is to keep
track of the number of decimal points.
Much better is to store the numbers as integers and convert to
decimal, guaranteeing zero loss.
Which are just different ways of saying “fixed point numbers” that matz
had at the top of his list. Believe me when I tell you that dealing
with fixed point can be challenging. I worked on part of an air traffic
control system about 20 years ago that used 16-bit values where the LSB
for a distance value represented 1/256nm (nautical mile). There was no
floating-point co-processor in the M68000-based systems and the C code
was compiled with a special, non-standard compiler that would do things
like (16-bits * 16-bits)/16-bits was assumed to produce a 16-bit result
unless you had a typecast to indicate otherwise.
I think we have a difference of understanding of what fixed point means.
I look at fixed point numbers meaning something like 1057 means 10.57
in the real world. I was thinking more of something that shifted the
floating point number to remove the fractions and later replaced the
decimal point in the correct position, which I do not consider to be
fixed point math.
My simple calculator is more precise for some math operations than my
expensive PC. Maybe we need to implement something like General Decimal
Arithmetic which is available for C++ and Java at http://www2.hursley.ibm.com/decimal/ in Ruby. It may be as simple as
writing wrappers for the operations, I haven’t had to time to look
closer at the package.
A simple way to get the correct figure is to do what is used often
with
currency to prevent these types of errors. If I enter ‘puts
1495.0*6.0/1000.0’ I get 8.97. The only thing necessary is to keep
track of the number of decimal points.
Much better is to store the numbers as integers and convert to
decimal, guaranteeing zero loss.
Which are just different ways of saying “fixed point numbers” that
matz had at the top of his list. Believe me when I tell you that
dealing with fixed point can be challenging. I worked on part of an
air traffic control system about 20 years ago that used 16-bit values
where the LSB for a distance value represented 1/256nm (nautical
mile). There was no floating-point co-processor in the M68000-based
systems and the C code was compiled with a special, non-standard
compiler that would do things like (16-bits * 16-bits)/16-bits was
assumed to produce a 16-bit result unless you had a typecast to
indicate otherwise.
The other way to get truth from 14.95*0.6 == 8.97 is to use less
precise representations than you get with a typical Float. Of
course, that’s going to be a problem as the numbers get bigger