[Tutor] Float precision untrustworthy~~~
Jacob S.
keridee at jayco.net
Fri Apr 1 01:23:32 CEST 2005
> 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
More information about the Tutor
mailing list