PeÃ±a wrote:

–snip–

Unfortunately, there is no easy solution to this problem. Here is a

catalog of often proposed solutions and why they do not work:

1 (proposed by doug meyer in this thread) Always use

(x-y).abs < Float::EPSILON

as a test for equality.

This won’t work because the rounding error easily can get bigger than

Float::EPSILON, especially when dealing with numbers that are bigger

than unity. e.g.

y = 100.1 + 0.3

y - 100.4 # => -1.421e-14, while Float::EPSILON = 2.22e-16

2 Always use

(x-y).abs < (x.abs + y.abs) * Float::EPSILON)

as a test for equality.

Better than the first proposal, but won’t work if the rounding error

gets too large after a complex computation.

In addition, (1) and (2) suffer from the problem that x==y and y==z do

not imply x==z.

3 Use Bigdezimal

This only shifts the problem a few decimal places down, and tests for

equality will fail as with the normal floats.

4 Use Rationals

Works if you only have to deal with rational operations. But doesn’t

solve the following

x = sqrt(2)

y = x + 1

x + 0.2 == y - 0.8 # => false

In addition, rational arithmetic can produce huge numbers pretty fast,

and this will slow down computations enormously.

5 Use a symbolic math package

This could in theory solve the issue with equality, but in practice

there

is no way to decide that two symbolic representations of a number are

the

same, like

1 / (sqrt(2) - 1) == sqrt(2) + 1

Also, very, very slow.

6 Use interval arithmetic

Gives you strict bounds on your solution, but can’t answer x==y.

Summing up, when using floating point arithmetic there is no one true

way.

There is no substitute for understanding numbers and analyzing your

problem.

HTH,

Michael