123.3 + 0.1 is 123.3999999999 ?

Isaac To kkto at csis.hku.hk
Fri May 16 04:57:08 EDT 2003


>>>>> "A" == A Puzzled User <kendear_nospam at nospam.com> writes:

    A> I think people won't like it if 12.95 becomes 12.94999999999 and some
    A> comparison fails such as checking if an item is more than or equal to
    A> $12.95 and the 12.94999999999 doesn't satisfy the >= 12.95 check.
    A> But if fact, it does -- because essentially, it is checking against
    A> itself.  12.949999999 >= 12.95 is true!  because 12.95 is stored as
    A> 12.949999999 anyways.

    A> Here is a test:

    >>>> a = 12.95 a
    A> 12.949999999999999
    >>>> if (a >= 12.95): print "more than my budget"

    A> more than my budget
    >>>>

    A> I suppose there is no situation that the inaccuracy can cause such
    A> obvious bugs?  I just wonder why the interactive command line gives
    A> us 12.949999999 while print 12.5 will give us 12.95.... why doesn't
    A> the command line lie also?

Anyone who know how to work on floating point numbers will know that they
must compare against 12.955 in such cases.  This is not new to anyone with
elementary statistics background: when people talk about class boundary they
are doing essentially the same thing.  (So in short, never do equality
comparison with floating point.)

Such relaxation is always important, whether or not it is a financial
application or a scientific one.  You can try writing a ray tracer in
whatever language you like using floating point numbers.  If you don't relax
the floating point comparisons a little bit, around half of the ray you
shoot into an object will have its reflection blocked by the same object.

Of course, if one is in financial apps, he has the option to use a decimal
class instead.  But I think it just hide the problem without solving it.
Sooner or later you will find that you need to perform divisions (e.g., to
convert between currencies), and at that time you have to lose accuracy
anyway.

And of course, if don't like inaccurate arithematics, he has the option to
use a rational class instead.  But I think it just hide the problem without
solving it.  Sooner or later you will find that you need to perform
logarithms (e.g., to compute present or future values), and at that time you
have to lose accuracy anyway.

Worse of all, both solutions lose time and space efficiency; and they tends
to lose accuracy *more* seriously than the binary representations once you
must lose accuracy.  So in short, believe in your float, calculate the
error, relax your comparison, and that's enough for most practical purposes.
In cases that this does not solve the problem, you probably have to work on
your representation in a much more careful way than a rational and decimal
class would provide.

Regards,
Isaac.




More information about the Python-list mailing list