Ruby doesn't know how to multiply

R

rjprado

Hello,

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!

I don't know if this is a bug. Please let me know. By the way i´m on
ruby 1.8.5. I'll give it a try on 1.8.6 and let you know.

Thanks,
Roberto Prado.
 
G

Gregory Brown

Hello,

Dear friends, today I have stumbled into a really weird problem. Try
typing this on irb:

14.95 * 0.6 =3D=3D 8.97

Ruby says it's false!

I don't know if this is a bug. Please let me know. By the way i=B4m on
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.

http://docs.sun.com/source/806-3568/ncg_goldberg.html
 
M

MenTaLguY

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.

-mental
 
A

Adriano Ferreira

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] =3D
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:

( 14.95 * 0.6 - 8.97 ).abs < tol

where tol depends on your application.
 
R

rjprado

Hello,

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!

I don't know if this is a bug. Please let me know. By the way i´m on
ruby 1.8.5. I'll give it a try on 1.8.6 and let you know.

Thanks,
Roberto Prado.

Yes, you are all right. It's a common problem. I have confirmed this
by doing the same thing on java. Thank you all for your fast replies.

Greetings,
Roberto Prado.
 
R

rjprado

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:

( 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...
 
M

MenTaLguY

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.

-mental
 
L

Lloyd Linklater

Yes, you are all right. It's a common problem. I have confirmed this
by doing the same thing on java. Thank you all for your fast replies.

I tried this in Delphi, smalltalk and oracle SQL and got the correct
result.

C# and visual C++ seem to it to be false.

This is most perplexing.
 
R

Rick DeNatale

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] =3D
0.0001100110011001100110011...[base 2]) and when they are represented
(as it happens with floating point representations), they lose
precision

Actually in any base there are fractions which cannot be represented with a
FINITE number of digits. For instance in base 10:

1/3 =3D 0.33333333333.......


--=20
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/
 
R

Rick DeNatale

Hi,

In message "Re: Ruby doesn't know how to multiply"

|I tried this in Delphi, smalltalk and oracle SQL and got the correct
|result.

Interesting. There are a few ways to get the "correct" result.

* fixed point number
* base 10 floating numbers
* comparison with epsilon

Does anyone know how these languages get the correct result?

matz,

I don't know which Smalltalk he used, but I just tried it in Squeak
and it evalutes to false, just like in Ruby.
 
S

Stefan Rusterholz

Shot said:
MenTaLguY:




Any particular reason against using Float::EPSILON here? :)

Maybe Float#== could simply be extended to consider the above? That
would most probably open another can of worms, though, and extending
Float#<=> would open yet another, I guess.

-- Shot

I think Float#== as it is is fine. Arguably it could use delta
comparison with Float::EPSILON and leave the exact comparison to eql?
But I'd like it if Float#in_delta(other, delta=Float::EPSILON) was in
core (personally I add it in my libs as Numeric#in_delta).

Regards
Stefan
 
G

Gregory Brown

I think Float#== as it is is fine. Arguably it could use delta
comparison with Float::EPSILON and leave the exact comparison to eql?
But I'd like it if Float#in_delta(other, delta=Float::EPSILON) was in
core (personally I add it in my libs as Numeric#in_delta).

I'd prefer in_delta?, but I think this is a great idea. Maybe you
should submit an RCR?
 
M

Mauricio Fernandez

Comparing floating-point values different from 1.0?

(also, greater errors)
I think Float#== as it is is fine. Arguably it could use delta
comparison with Float::EPSILON and leave the exact comparison to eql?
But I'd like it if Float#in_delta(other, delta=Float::EPSILON) was in
core (personally I add it in my libs as Numeric#in_delta).

That default value for delta makes no sense in general if you're using it as
in the above example.

Comparing the absolute difference against a fixed epsilon (especially
Float::EPSILON) isn't normally as interesting as giving a bound for the
relative error, so you'd at least need something like

class Float
def in_rdelta(other, rdelta = 1e-6) # or maybe no default at all?
return true if self == other
d = self.abs > other.abs ? (self - other) / self : (self - other) / other
d.abs <= rdelta
end
end

e = Float::EPSILON # => 2.22044604925031e-16
1.0.in_rdelta(1.000000000000000222, e) # => true
100.0.in_rdelta(100.000000000000021, e) # => true
100.0.in_rdelta(100.000000000000044, e) # => false
1.0.in_rdelta(1.000000000000000322, e) # => true
1.000000000000000322 == 1.000000000000000222 # => true
"%20.18f" % 1.000000000000000322 # => "1.000000000000000222"

# And you'd have to add an extra check if you want a different semantics
# around 0.0:

0.0.in_rdelta(2.22e-16, 0.1) # => false
0.0.in_rdelta(2e-17, 0.99) # => false
0.0.in_rdelta(2e-20, 0.9999) # => false
 
G

Gregory Brown

class Float
def in_rdelta(other, rdelta = 1e-6) # or maybe no default at all?

I'd say no default.

If you're already doing a check for something being in delta of
something else, you might as well specify what you're looking for.
 
L

Lloyd Linklater

Logan said:
VisualWorks 7.4? (At least that seems to be a smalltalk with a version
number of 7.4).

(You are aware that theres more than one implementation of Smalltalk,
and to
give just a version number is very vague, right?)

oops! Sorry. Yes, it is VisualWorks 7.4
 

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

Forum statistics

Threads
474,262
Messages
2,571,310
Members
47,977
Latest member
MillaDowdy

Latest Threads

Top