floating point glitch

D

David O'Farrell

Is this only on solaris ?

Python 2.3.3 (#1, Mar 19 2004, 16:18:33)
[GCC 2.95.2 19991024 (release)] on sunos5
Type "help", "copyright", "credits" or "license" for more information.
>>> a=[66.6, 333, 333, 1, 1234.5]
>>> print a.count(333), a.count(66.6), a.count('x') 2 1 0
>>> a.append(333)
>>> print a
[66.599999999999994, 333, 333, 1, 1234.5, 333]
 
P

Paul Rubin

David O'Farrell said:
Is this only on solaris ?

No, it's inherent in how floating point conversions work. It happens
on all IEEE 754 machines. You don't need that fancy list-append stuff
to see it happen. Just type
66.599999999999994
 
C

Cameron Laird

No, it's inherent in how floating point conversions work. It happens
on all IEEE 754 machines. You don't need that fancy list-append stuff
to see it happen. Just type

66.599999999999994

Next time someone tries to Wikify the definitive response to these
FAQs (I don't feel up to it myself, this week), let me recommend
mention of "Computing over the Reals: Where Turing Meets Newton"
<URL: http://www.ams.org/notices/200409/fea-blum.pdf >.
 
T

Tim Roberts

David O'Farrell said:
Is this only on solaris ?

Every IEEE754 processor, every language.
Python 2.3.3 (#1, Mar 19 2004, 16:18:33)
[GCC 2.95.2 19991024 (release)] on sunos5
Type "help", "copyright", "credits" or "license" for more information.
a=[66.6, 333, 333, 1, 1234.5]
print a.count(333), a.count(66.6), a.count('x') 2 1 0
a.append(333)
print a
[66.599999999999994, 333, 333, 1, 1234.5, 333]

This is a FAQ. The short answer is that 66.6 cannot be represented exactly
in binary. It is an infinitely repeating fraction. (1234.5 is not, which
is why the same thing didn't happen to it.)

When you use print, it calls repr() to get the string representation. repr
tells you the exact value, as close as possible. That value is as close as
you can get to 66.6 using a 64-bit IEEE754 float.

str() lies to you to make you happy:
66.6
 
M

Michael Hoffman

Tim said:
a=[66.6, 333, 333, 1, 1234.5]
print a.count(333), a.count(66.6), a.count('x')

2 1 0
a.append(333)
print a

[66.599999999999994, 333, 333, 1, 1234.5, 333]

This is a FAQ. The short answer is that 66.6 cannot be represented exactly
in binary. It is an infinitely repeating fraction. (1234.5 is not, which
is why the same thing didn't happen to it.)

When you use print, it calls repr() to get the string representation.

Actually, print essentialy uses str() to get the string representation.
But repr(list) or str(list) still gets the repr() of each item of the
list rather than the str():
.... def __str__(self):
.... return "<str() called>"
.... def __repr__(self):
.... return said:
>>> t = TestObject()
>>> str(t)
' said:
>>> repr(t)
' said:
>>> print t
>>> l = [TestObject()]
>>> str(l)
'[ said:
>>> repr(l)
'[ said:
>>> print l
[ said:
[<repr() called>]

One way around this is to call str for each item yourself:
>>> "[%s]" % ", ".join(map(str, l))
'[<str() called>]'

You could also define a list subclass that does this for you.
 
T

Tim Roberts

Paul Rubin said:
Michael Hoffman said:
Actually, print essentialy uses str() to get the string
representation. But repr(list) or str(list) still gets the repr() of
each item of the list rather than the str():
print .66 0.66
print [.66]
[0.66000000000000003]

Yucch! Also, str is not invertible:

Right! That's the point. str() is the perfect solution in those cases
where you want the language to lie to you. In many cases, that IS what you
want. repr() is the perfect solution when you need an invertible function.

And that's really the lesson that needs to be taught when this FAQ is A-ed.
 
P

Paul Foley

Paul Rubin said:
Michael Hoffman said:
Actually, print essentialy uses str() to get the string
representation. But repr(list) or str(list) still gets the repr() of
each item of the list rather than the str():
print .66 0.66
print [.66]
[0.66000000000000003]

Yucch! Also, str is not invertible:
Right! That's the point. str() is the perfect solution in those cases
where you want the language to lie to you. In many cases, that IS what you
want. repr() is the perfect solution when you need an invertible function.

The "perfect solution" is either: (a) to print the minimal number of
digits that can maintain print/read consistency -- in this case, that
means printing "0.66", or (b) to print the actual, exact, decimal
representation of the value -- in this case, that means printing
"0.66000000000000003108624468950438313186168670654296875"

And I think (a) is more perfect than (b) :)
 
P

Paul Rubin

Paul Foley said:
The "perfect solution" is either: (a) to print the minimal number of
digits that can maintain print/read consistency -- in this case, that
means printing "0.66",

Nah, you can do that by printing everything as zero.
 
P

Piet van Oostrum

PR> Nah, you can do that by printing everything as zero.

That would not maintain print/read consistency, i.e. if you read back the
printed value you don't get the original value.
 
P

Paul Rubin

Piet van Oostrum said:
PR> Nah, you can do that by printing everything as zero.

That would not maintain print/read consistency, i.e. if you read back the
printed value you don't get the original value.

The current conversion doesn't have that property.
False
 
P

Piet van Oostrum

PR> The current conversion doesn't have that property.
PR> False

That's because print uses str rather than repr:
True
 
M

Michael Hoffman

Tim said:
Right! That's the point. str() is the perfect solution in those cases
where you want the language to lie to you. In many cases, that IS what you
want. repr() is the perfect solution when you need an invertible function.

repr() does not provide an invertible function if you are using it on a
list, as was pointed out here, since list.__repr__() essentially calls
str() for its float members rather than repr().
 
P

Peter Hansen

Michael said:
repr() does not provide an invertible function if you are using it on a
list, as was pointed out here, since list.__repr__() essentially calls
str() for its float members rather than repr().

It does?
>>> [0.66] [0.66000000000000003]
>>> repr([0.66]) [0.66000000000000003]'
>>> str([0.66]) [0.66000000000000003]'
>>> str(0.66) '0.66'
>>> repr(0.66)
'0.66000000000000003'


-Peter
 
A

Alex Martelli

Michael Hoffman said:
repr() does not provide an invertible function if you are using it on a
list, as was pointed out here, since list.__repr__() essentially calls
str() for its float members rather than repr().

?! I think you're confused, since things are exactly the other way
around: list.__str__ calls repr on its members (so does list.__repr__,
which happens to be exactly the same function).

repr isn't necessarily perfect in all cases, but it does do a creditable
job on many built-in types -- including all kinds of built-in numbers,
strings, and containers whose leaves are such numbers and strings.


Alex
 
M

Michael Hoffman

Alex said:
?! I think you're confused, since things are exactly the other way
around: list.__str__ calls repr on its members (so does list.__repr__,
which happens to be exactly the same function).

Yep, I got that exactly backwards. D'oh!

Thanks Alex and I'm sorry for any confusion I caused.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top