Precision issue

Stephen Horne $$$$$$$$$$$$$$$$$ at $$$$$$$$$$$$$$$$$$$$.co.uk
Fri Oct 10 10:14:52 EDT 2003


On 10 Oct 2003 22:38:22 +0950, Ben Finney
<bignose-hates-spam at and-benfinney-does-too.id.au> wrote:

>On Fri, 10 Oct 2003 10:36:16 +0000 (UTC), Duncan Booth wrote:
>> I know this is an FAQ, but the one thing I've never seen explained
>> satisfactorily is why repr(3.4) has to be '3.3999999999999999' rather
>> than '3.4'?
>
>Because '3.4' is what str(3.4) returns.  If repr(3.4) lies about the
>value stored, what function will you leave us to discover the actual
>value?
>
>The str() function is for getting the working output of the value.  The
>repr() function is for discovering, as precisely as possible, the actual
>value.

Is there a basis for that claim?

My impression has always been that 'repr' gives a representation of
the value which, when parsed (using 'eval', for instance),
reconstructs the original value. In this respect, '3.4' is just as
good as '3.3999999999'.

IIRC, a binary float can always be given a precise decimal
representation - it simply tends to take a lot of digits. The fact
that repr doesn't give a perfect representation of the binary float
value suggests that it is not 'for discovering, as precisely as
possible, the actual value'.

Out of curiosity, I wrote the function at the bottem of this post to
convert a Python float into two string representations - a rational
and a decimal - both having precisely the same value as the float. I
got the following results starting with 3.4...

Rational : 7656119366529843/2251799813685248
Decimal  : 3.399999999999999911182158029987476766109466552734375

I don't guarantee that the code is bug free - it may well be very
fragile, depending on platform specific float handling - but I believe
these results are accurate. For the record, I'm running Python 2.3
under Windows 2000 on a Pentium 4.

I am not aware of a Python standard function which will give this
rather impractical level of precision. But if Pythons repr function
was intended 'for discovering, as precisely as possible, the actual
value', it really should give the decimal value from above which it is
clearly possible to discover. The truth is, however, that such
discovery is rarely if ever useful - floats are inherently approximate
values.

Converting float values to decimal is almost always either for the
benefit of human readers, or for creating text representations that
will be converted back to floats at some point. str serves the first
purpose well. For the second, the important identity is that
eval(repr(x)) == x (or at least a sufficiently close approximation -
I'm not sure if repr currently preserves the full precision of the
float).


Here's the code...

def perfect (val) :
  #  Convert to rational
  
  num = 0
  denom = 1
  
  #  handle integer part
  
  num = int(val)
  val -= num
  
  #  handle fractional part
  
  while val != 0 :
    val *= 2
    num *= 2
    denom *= 2
  
    if val >= 1 :
      num += 1
      val -= 1

  rat = str(num)+"/"+str(denom)
  
  #  convert to decimal form
  
  dec = str(num/denom) + "."
  num = num % denom
  
  while num > 0 :
    num *= 10
    dec += str(num / denom)
    num = num % denom

  return (rat, dec)


-- 
Steve Horne

steve at ninereeds dot fsnet dot co dot uk




More information about the Python-list mailing list