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!)
Yeah, but it threw me for a loop, because I could find *no*e way to compare a
float and an integer and get it to come out right before I remembered round.
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 ###
Wish granted in version 2.4 ;-) I don't have it on the mac, but there is a write-up at
I meant in the scripts -- even better, as a builtin.
Your above helper function is fine... but I believe that it should be part of the __cmp__ method of the float types. Perhaps with optional parameter? Such as oldway=True
Jacob Schmidt
_______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor