Precision issue

Stephen Horne $$$$$$$$$$$$$$$$$ at $$$$$$$$$$$$$$$$$$$$.co.uk
Fri Oct 10 07:47:45 EDT 2003


On Fri, 10 Oct 2003 09:54:12 GMT, Alex Martelli <aleax at aleax.it>
wrote:

>Ladvánszky Károly wrote:
>
>> Entering 3.4 in Python yields 3.3999999999999999.
>> I know it is due to the fact that 3.4 can not be precisely expressed by
>> the powers of 2. Can the float handling rules of the underlying layers be
>> set from Python so that 3.4 yield 3.4?
>
>It seems, from the question, that you might not have entirely understood
>and grasped the explanations you can find at:
>http://www.python.org/doc/current/tut/node14.html
>and I quote, in particular:
>"""
>no matter how many base 2 digits you're willing to use, the decimal value
>0.1 cannot be represented exactly as a base 2 fraction.
>"""

There are simple workarounds for this, though. For instance, if
someone needs one or two decimal digits of precision, they can simply
hold all values scaled by 10 or 100 - while neither 0.01 nor 0.1 can
be precisely represented as a binary value, 1 can be.

Actually, scaling by 100 is overkill - the nearest power of two is
128, and 100/128 is equivalent to 25/32, so a scale factor of 25
should be sufficient to allow two decimal digits of precision.
However, there is probably no advantage to scaling by 25 instead of
100 - just the disadvantage that the purpose of the scaling is less
obvious.

Anyway, this could be what Ladvánszky Károly meant, I suppose, by
'float handling rules of the underlying layers'. Of course this can't
be done using the existing float class as Python doesn't define the
float handling rules - they are presumably defined in most cases by
the floating point logic built into the CPU.

Perhaps Ladvánszky Károly has used Ada, where you can request a fixed
point or floating point type with particular properties and it is up
to the compiler to find or create one to suit. Though IIRC its floats
are still always binary floats - only its fixed point values can
handle decimals as Ladvánszky Károly has requested.

There are also, of course, languages which support different numeric
types such as a decimal type - Java has BigDecimal and C# has Decimal
(the C# one works using a fixed point scaling where the scaling must
be a power of 10, Java BigDecimal is IIRC more powerful - arbitrary
scale and precision, I think).

The issue of alternate numeric representations does get raised from
time to time, as I'm sure Alex knows better than me. There are
packages around. One key problem is that different people want
different things. A person who wants a fixed-point number class, for
instance, is not going to want the additional overhead from a rational
number class. Even a symbolic expression class has been suggested in
the past.

One common need for decimals is for currency values. This need can be
avoided by simply storing currency values in pence/cents rather than
pounds/dollars. Similarly, percentages can be handled using integer
calculations. For example, adding 17.5% (for UK VAT, perhaps) can be
handled using floats as follows...

  result = value * 1.175

or using integers as follows...

  result = (value * 1175) / 1000

In the example above, the parentheses are unnecessary but included to
emphasise the order of the calculations, which is important.

In my experience, this method handles most cases where results need to
be consistent with decimal arithmetic - store values using appropriate
units and the problem usually goes away.


-- 
Steve Horne

steve at ninereeds dot fsnet dot co dot uk




More information about the Python-list mailing list