On Monday, Mar 28, 2005, at 22:11 America/Chicago, [EMAIL PROTECTED] wrote:
[cut]
the mere fact that floats are difficult to check with equality has bitten me more than anything I've met yet in python.
[cut]
I understand what you are talking about, but I tend toward just making it one of the things to remember when working with floats. (I've been bitten a lot when I forget to use '==' instead of '=', too!)
As you say, the problems arise when you try to make comparisons. To get around the difficulties with comparisons, I wrote a helper function:
###
Python 2.3 (#2, Jul 30 2003, 11:45:28)
[GCC 3.1 20020420 (prerelease)]
Type "copyright", "credits" or "license" for more information.
MacPython IDE 1.0.1
>>> from math import floor, log10
>>> def Round(x, n=0, sigfigs=False):
'''An enhanced rounder which rounds to the nth significant digit
(the nth digit from the first non-zero digit, not the nth decimal place)
if the parameter sigfigs is not zero.
This uses "round-up" decisions when the digit following the one of
interest is a 5, i.e. 1.35 and 1.45 Round to 1.4 and 1.5 when sigfigs = 2.
'''
if x==0: return 0
if not sigfigs:
return round(x,n)
else:
return round(x,n-1-int(floor(log10(abs(x)))))
###
And here's a helper that uses it to check for equality of two numbers (floats, or otherwise)
to whatever number of digits you desire --starting from the first non-zero digit, The default is for high precision.
###
>>> def same(x,y,prec=9):
"""Return True if x and y are the same after being rounded to the same degree of precision."""
return Round(x,prec,1)==Round(y,prec,1)
..
>>> print same(1.3,1.31,3) #at the 3rd digit these are different
False
>>> print same(1.3,1.31,2) #at the second digit they are (rounded to) the same digit number
True
>>> same(64.0**(1/3.0) ,4) #here's your example
True
###
You can be bitten by any comparison, not only tests for equality, too.
### >>> while 1: .. i+=.1 .. if i>2.1:break .. >>> print i 2.1 ###
It doesn't look like the last value of i was really greater than 2.1--it's actually 2.1000000000000005 so the result is correct (though not what we expected). We don't have the problem with a step size of 0.7 in this case, though, because the value before 2.8 was 2.0999999999999996--just a little smaller than 2.1.
Here, we specify the precision and get the desired result.
### >>> i=0 >>> while 1: .. i+=.1 .. if round(i,9)>round(2.1,9):break .. >>> print i 2.2 ###
[cut]
The last three checks also show that you need to define the places argument
to get a good answer. Why not just implement decimal or some equivalent and
get rid of hidden, hard to debug headaches? I understand uses of floats
where the precision isn't exact anyway -- i.e. sqrt(2)
Wish granted in version 2.4 ;-) I don't have it on the mac, but there is a write-up at
http://www.python.org/doc/2.4/whatsnew/node9.html
The starting blurb says:
"Python has always supported floating-point (FP) numbers, based on the underlying C double type, as a data type. However, while most programming languages provide a floating-point type, many people (even programmers) are unaware that floating-point numbers don't represent certain decimal fractions accurately. The new Decimal type can represent these fractions accurately, up to a user-specified precision limit. "
/c
_______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor