# [Newbies] Re: [BUG] Inconsistent float soustraction

johnps11 at bigpond.com johnps11 at bigpond.com
Sun Feb 17 20:56:40 UTC 2008

```Cedric,

Part of the issue is that different architectures will have different
values for machine epsilon (1e-09 in your post).  Machine epsilon is
defined to be the largest float such that

0.0 + epsilon = 0.0

Its value varies according to your machine though - typically a machine
with a much larger machine word size in its floating point processor will
have a much smaller machine epsilon. (The following is an example of a
Simple Lie, for an introduction to the Complicated Truth I suggest you get
hold of a book on Numerical Computation, which is an important study in
Computer Science).

Things are complicated further in that in any radix based number system
there are very simple numbers that cannot be written exactly.  In the
decimal number system any fraction with a denominator relatively prime to
the radix tends to be an infinitely repeating fraction. 1/3 or 3/7 are
examples.

Computers use binary numbers inside. 1/10 is not expressible as a
nonrecurring binary fraction, nor is 1/3, 3/10, 2/5 or 1/20.

Squeak does a good job of trying to promote numbers to ScaledDecimals, but
they are much more expensive to calculate than IEEE floats or Integers.

If we repeat your examples using Fractions we get

1 - (2/10) - (5/100) - ( 3/10) - (1/10) -(1/10) = (1/4) true

because Fractions are exact - in fact the definition of equality for
fractions is defined to be

( a/b ) = ( c/d ) if and only if ( a * d ) = (b * c)

which only uses Integer and BigNum arithmetic and allows arbitrary
precision (unless the numbers are so big you run out of memory).

Your idea of redefining equality for floats is a very bad idea because (1)
it assumes all hardware has the same value for machine epsilon and (2)
will break 50 years worth of programs that do numerical computation.

The simplest rule is any attempt to test floats (or doubles, or IEEE
decwords) for equality is a bug.  If there's a decimal point in your
calculations (or if there could be) then don't test for equality.  This is
taught to computing students at University in the first few weeks.  Any
work done by a Uni student who breaks this rule gets marked down very
severely!

I commend you on discovering this on your own by the way - it shows an
inquiring mind.  It's not everyone who hits one of the key issues in
Computer Science by themselves, and then thinks about it.

Yours,

John.

>> > Hi,
>> >
>> > I noticed in my image (damien last beta so 3.10 - windows XP and
>> > Vista) that I have a strange bug when soustracting floats
>> > successively. Here is how I reproduce it in a workspace:
>> >
>> > 1 - 0.2 -0.05 -0.3 = 0.45 "true"
>> > 1 - 0.2 -0.05 -0.3 -0.1= 0.35  "true"
>> > 1 - 0.2 -0.05 -0.3 -0.1 - 0.10= 0.25  "*****false*****"
>> > 1 - 0.2 -0.05 -0.3 -0.1 - 0.10= 0.24999999999999995   true
>> >
>> > or again:
>> > 1 - 0.1 = 0.9  true
>> > 1 - 0.1 - 0.1 = 0.8 true
>> > 1 - 0.1 - 0.1 - 0.1 = 0.7 false
>> >
>> >
>> > Can somebody explain that or is it a bug ? I don't know yet if it's
>> > specific to my image, so does other have the same behavior?
>> > I can force the rounding of the result but find it strange.
>> >
>
> 2008/2/17, danil osipchuk <danil.osipchuk at gmail.com>:
>> This is not even squeak specific. Decimal floats not always can be
>> represented precisely in binary form:
>>
>> http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
>>
>
>
>>
>>         if you need to operate with exact precision just don't trust
>> floats. Use ScaledDecimals instead. In Squeak ScaledDecimals are
>> implemented with the fraction so it's matematically stronger
>> than floats. Use floats at presentation or user interface time
>> and evade them at domain model.
>>
>>         cheers,
>>
>> Sebastian Sastre
>
> uhm ok, good to know.
> Actually, it was just a test that failed so I was surprised.
>
> I still find the result odd.
>
> Seeing ScaledDecimal>>testConvertFromFloat, I'm wandering if it would
> be better to have Float>>=   considering egality if the difference is
> less than 1.0e-9.
>
> <primitive: 47>
> aNumber isNumber ifFalse: [^ false].
> ^ (aNumber asFloat - self) abs  <  1.0e-9
>
> I would prefer having = working as I expect, even if it would be wrong
> for smaller values than 1.0e-9. For strict egality, == can be used.
>
> Is it possible to disable a primitive call like here (it's optimized no ?)
> ?
>