Re: [Python-Dev] math.areclose ...?
A problem that I pointed out with the proposed areclose() function is that it has within it a fp comparison. If such a function is to have greater utility, it should allow the user to specify how significant to consider the computed error. A natural extension of being able to tell if 2 fp numbers are close is to make a more general comparison. For that purpose, a proposed fpcmp function is appended. From that, fp boolean comparison operators (le, gt, ...) are easily constructed. Python allows fp comparison. This is significantly of source of surprises and learning experiences. Are any of these proposals of interest for providing tools to more intelligently make the fp comparisons? ### #new proposal for the areclose() function def areclose(x,y,atol=1e-8,rtol=1e-5,prec=12): Return False if the |x-y| is greater than atol or greater than the absolute value of the larger of x and y, otherwise True. The comparison is made by computing a difference that should be 0 if the two numbers satisfy either condition; prec controls the precision of the value that is obtained, e.g. 8.3__e-17 is obtained for (2.1-2)-.1. But rounding to the 12th digit (the default precision) the value of 0.0 is returned indicating that for that precision there is no (significant) error. diff = abs(x-y) return round(diff-atol,prec)=0 or \ round(diff-rtol*max(abs(x),abs(y)),prec)=0 #fp cmp def fpcmp(x,y,atol=1e-8,rtol=1e-5,prec=12): Return 0 if x and y are close in the absolute or relative sense. If not, then return -1 if x y or +1 if x y. Note: prec controls how many digits of the error are retained when checking for closeness. if areclose(x,y,atol,rtol,prec): return 0 else: return cmp(x,y) # fp comparisons functions def lt(x,y,atol=1e-8,rtol=1e-5,prec=12): return fpcmp(x, y, atol, rtol, prec)==-1 def le(x,y,atol=1e-8,rtol=1e-5,prec=12): return fpcmp(x, y, atol, rtol, prec) in (-1,0) def eq(x,y,atol=1e-8,rtol=1e-5,prec=12): return fpcmp(x, y, atol, rtol, prec)==0 def gt(x,y,atol=1e-8,rtol=1e-5,prec=12): return fpcmp(x, y, atol, rtol, prec)==1 def ge(x,y,atol=1e-8,rtol=1e-5,prec=12): return fpcmp(x, y, atol, rtol, prec) in (0,1) def ne(x,y,atol=1e-8,rtol=1e-5,prec=12): return fpcmp(x, y, atol, rtol, prec)0 ### ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
Please, I don't much care about the fine points of the function's semantics, but PLEASE rename that function to are_close. Every time I see this subject in my email client I have to think for a few seconds what the hell 'areclose' means. This time it's not just because of the new PEP 8, 'areclose' is really really hard to read. -- Gustavo J. A. M. Carneiro [EMAIL PROTECTED] [EMAIL PROTECTED] The universe is always one step beyond logic ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
Smith wrote: ... There is a problem with dividing by 'ave' if the x and y are at the floating point limits, but the symmetric behaving form (presented by Scott Daniels) will have the same problem. Upon reflection, 'max' is probably better than averaging, and avoiding divide is also a reasonably good idea. Note that relative_tol 1.0 (typically) so underflow, rather than overflow, is the issue: def nearby(x, y, relative_tol=1.e-5, absolute_tol=1.e-8): difference = abs(x - y) return (difference = absolute_tol or difference = max(abs(x), abs(y)) * relative_tol) I use =, since zero-tolerance should pass equal values. --Scott David Daniels [EMAIL PROTECTED] ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
Raymond Hettinger wrote: | [Chris Smith] || Does it help to spell it like this? || || def areclose(x, y, relative_err = 1.e-5, absolute_err=1.e-8): || diff = abs(x - y) || ave = (abs(x) + abs(y))/2 || return diff absolute_err or diff/ave relative_err | | There is a certain beauty and clarity to this presentation; however, | it is problematic numerically: | | * the division by either absolute_err and relative_err can overflow or | trigger a ZeroDivisionError I'm not dividing by either of these values so that shouldn't be a problem. As long as absolute_err is not 0 then the first test would catch the possiblity that x==y==ave==0. (see below) As for the overflow, does your version of python overflow? Mine (2.4) just returns 1.#INF which still computes as a number: ### 1.79769313486e+308+1.79769313486e+308 1.#INF inf=_ inf1 True inf1 False 2./inf 0.0 inf/inf -1.#IND ### There is a problem with dividing by 'ave' if the x and y are at the floating point limits, but the symmetric behaving form (presented by Scott Daniels) will have the same problem. The following format for close() has the same semantic meaning but avoids the overflow possibility and avoids extra work for the case when abs_tol=0 and x==y: ### def close(x, y, abs_tol=1.e-8, rel_tol=1.e-5): '''Return True if |x-y| abs_tol or |x-y|/ave(|x|,|y|) rel_tol. The average is not computed directly so as to avoid overflow for numbers close to the floating point upper limit.''' if x==y: return True diff = abs(x - y) if diff abs_tol: return True f = rel_tol/2. if diff f*abs(x) + f*abs(y): return True return False ### | | * the 'or' part of the expression can introduce an unnecessary | discontinuity in the first derivative. | If a value other than boolean were being returned, I could see the desire for continuity in derivative. Since the original form presents a boolean result, however, I'm having a hard time thinking of how the continuity issue comes to play. | The original Numeric definition is likely to be better for people who | know what they're doing; however, I still question whether it is an | appropriate remedy for the beginner issue | of why 1.1 + 1.1 + 1.1 doesn't equal 3.3. | I'm in total agreement. Being able to see that math.areclose(1.1*3,3.3) is True but 1.1*3==3.3 is False is not going to make them feel much better. They are going to have to face the floating point issue. As for the experienced user, perhaps such a function would be helpful. Maybe it would be better to require that the tolerances be given rather than defaulting so as to make clear which test is being used if only one test was going to be used: close(x,y,rel_tol=1e-5) close(x,y,abs_tol=1e-8) /c ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
On Mon, Feb 06, 2006, Chris or Leslie Smith wrote: Aahz: Alex: || def areclose(x,y,rtol=1.e-5,atol=1.e-8): || return abs(x-y)atol+rtol*abs(y) | | Looks interesting. I don't quite understand what atol/rtol are, | though. Does it help to spell it like this? def areclose(x, y, relative_err = 1.e-5, absolute_err=1.e-8): diff = abs(x - y) ave = (abs(x) + abs(y))/2 return diff absolute_err or diff/ave relative_err Also, separating the two terms with 'or' rather than '+' makes the two error terms mean more what they are named. The '+' mixes the two effects and even though the result is basically the same, it makes it difficult to explain when the test will be true. Yes, that's a big help. I was a bit concerned that this would have no utility for numbers with large magnitude. Alex, given your focus on Python readability, I'm a bit surprised you didn't write this to start with! -- Aahz ([EMAIL PROTECTED]) * http://www.pythoncraft.com/ 19. A language that doesn't affect the way you think about programming, is not worth knowing. --Alan Perlis ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
On 2/6/06, Aahz [EMAIL PROTECTED] wrote: ... def areclose(x, y, relative_err = 1.e-5, absolute_err=1.e-8): diff = abs(x - y) ave = (abs(x) + abs(y))/2 return diff absolute_err or diff/ave relative_err Also, separating the two terms with 'or' rather than '+' makes the two error terms mean more what they are named. The '+' mixes the two effects and even though the result is basically the same, it makes it difficult to explain when the test will be true. Yes, that's a big help. I was a bit concerned that this would have no utility for numbers with large magnitude. Alex, given your focus on Python readability, I'm a bit surprised you didn't write this to start with! As I said, I was just copying the definition in Numeric, which is well-tried by long use. Besides, this clear expression could present problems, such as possible overflows or divisions by zero when ave is 0 or very small; much as I care about readability, I care about correctness even more. Once it comes to readability, I prefer Numeric's choice to call the two terms tolerances, rather than (as here) errors; maybe that depends on my roots being in engineering, where an error means a mistake (like it does in real life), while tolerance's a good and useful thing to have (ditto), rather than some scientific discipline where terms carry different nuances. Alex ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
[Chris Smith] Does it help to spell it like this? def areclose(x, y, relative_err = 1.e-5, absolute_err=1.e-8): diff = abs(x - y) ave = (abs(x) + abs(y))/2 return diff absolute_err or diff/ave relative_err There is a certain beauty and clarity to this presentation; however, it is problematic numerically: * the division by either absolute_err and relative_err can overflow or trigger a ZeroDivisionError * the 'or' part of the expression can introduce an unnecessary discontinuity in the first derivative. The original Numeric definition is likely to be better for people who know what they're doing; however, I still question whether it is an appropriate remedy for the beginner issue of why 1.1 + 1.1 + 1.1 doesn't equal 3.3. Raymond ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
2006/2/6, Raymond Hettinger [EMAIL PROTECTED]: The original Numeric definition is likely to be better for people who know what they're doing; however, I still question whether it is an appropriate remedy for the beginner issue of why 1.1 + 1.1 + 1.1 doesn't equal 3.3. Beginners won't know about math.areclose anyway (and if they will, they won't use it, thinking why bother?), and having a standard, well-behaved and *correct* version of a useful function can't hurt. -- { Marek BaczyĆski :: UIN 57114871 :: GG 161671 :: JID [EMAIL PROTECTED] } { http://www.vlo.ids.gda.pl/ | imbaczek at poczta fm | http://www.promode.org } .. .. .. .. ... ... .. evolve or face extinction .. ... ... .. .. .. .. ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
Alex Martelli wrote: On 2/6/06, Aahz [EMAIL PROTECTED] wrote: ... def areclose(x, y, relative_err = 1.e-5, absolute_err=1.e-8): diff = abs(x - y) ave = (abs(x) + abs(y))/2 return diff absolute_err or diff/ave relative_err Also, separating the two terms with 'or' rather than '+' makes the two error terms mean more what they are named. The '+' mixes the two effects and even though the result is basically the same, it makes it difficult to explain when the test will be true. Yes, that's a big help. I was a bit concerned that this would have no utility for numbers with large magnitude. Alex, given your focus on Python readability, I'm a bit surprised you didn't write this to start with! As I said, I was just copying the definition in Numeric, which is well-tried by long use. Besides, this clear expression could present problems, such as possible overflows or divisions by zero when ave is 0 or very small; much as I care about readability, I care about correctness even more. It looks like the definition from Numeric measures relative error while the above measure relative deviation. I'm not sure which one would be desirable or if they are interchangeable. I was looking up relative error to try and understand the above at the following site. http://mathforum.org/library/drmath/view/65797.html As far as beginner vs advanced users are concerned I think that is a matter of documentation especially when intermediate users are concerned which I believe are the majority. Possibly something like the following would be suitable... ? The absolute error is the absolute value of the difference between the accepted value and the measurement. Absolute error = abs( Observed - Accepted value ) The Relative err is the percentage of absolute err relative to the accepted value. Absolute error Relative error = -- x 100% Accepted value def isclose(observed, accepted, abs_err, rel_err): Determine if the accuracy of a observed value is close to an accepted value diff = abs(observed, accepted) if diff abs_err: return True try: return 100 * abs_diff / accepted rel_err except ZeroDivisionError: pass return False Cheers, Ron Adam ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
On Sun, Feb 05, 2006, Alex Martelli wrote: But pulling in the whole of Numeric just to have that one handy function is often overkill. So I was wondering if module math (and perhaps by symmetry module cmath, too) shouldn't grow a function 'areclose' (calling it just 'close' seems likely to engender confusion, since 'close' is more often used as a verb than as an adjective; maybe some other name would work better, e.g. 'almost_equal') taking two float arguments and optional tolerances and using roughly the same specs as Numeric, e.g.: def areclose(x,y,rtol=1.e-5,atol=1.e-8): return abs(x-y)atol+rtol*abs(y) Looks interesting. I don't quite understand what atol/rtol are, though. You're right that another name would be better; almost_equal is fine. -- Aahz ([EMAIL PROTECTED]) * http://www.pythoncraft.com/ 19. A language that doesn't affect the way you think about programming, is not worth knowing. --Alan Perlis ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
Alex Martelli wrote: When teaching some programming to total newbies, a common frustration is how to explain why a==b is False when a and b are floats computed by different routes which ``should'' give the same results (if arithmetic had infinite precision). Decimals can help, but another approach I've found useful is embodied in Numeric.allclose(a,b) -- which returns True if all items of the arrays are ``close'' (equal to within certain absolute and relative tolerances): (1.0/3.0)==(0.1/0.3) False Numeric.allclose(1.0/3.0, 0.1/0.3) 1 But pulling in the whole of Numeric just to have that one handy function is often overkill. So I was wondering if module math (and perhaps by symmetry module cmath, too) shouldn't grow a function 'areclose' (calling it just 'close' seems likely to engender confusion, since 'close' is more often used as a verb than as an adjective; maybe some other name would work better, e.g. 'almost_equal') taking two float arguments and optional tolerances and using roughly the same specs as Numeric, e.g.: def areclose(x,y,rtol=1.e-5,atol=1.e-8): return abs(x-y)atol+rtol*abs(y) What do y'all think...? atol sounds suspicious to me, but otherwise fine. Georg ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
So I was wondering if module math (and perhaps by symmetry module cmath, too) shouldn't grow a function 'areclose' (calling it just 'close' seems likely to engender confusion, since 'close' is more often used as a verb than as an adjective; maybe some other name would work better, e.g. 'almost_equal') taking two float arguments and optional tolerances and using roughly the same specs as Numeric, e.g.: def areclose(x,y,rtol=1.e-5,atol=1.e-8): return abs(x-y)atol+rtol*abs(y) IMO, the cure is worse than the disease. It is easier to learn about the hazards of floating point equality testing than to think through the implications of tolerance testing (such as loss of transitivity) and learning how to set the right tolerance values for a given application (ones that give the right results across the entire domain of expected inputs). The areclose() function can be a dangerous crutch that temporarily glosses over the issue. Without some numerical sophistication, it would not be hard create programs that look correct and pass a few test but, in fact, contain nasty bugs (non-termination, incorrect acceptance/rejection, etc). rant This proposal is one of several that have recently surfaced that aim to help newbies skip learning basic lessons. I think the efforts are noble but misguided. * If someone doesn't get why set(1,2,3) raises an exception, it is a good opportunity to teach a broadly applicable skill: def Set(*args): return set(args) * If someone doesn't get why sum([0.1]*10)!=1.0, then we have a good opportunity to teach the basics of floating point. Otherwise, we're going to get people writing accounting apps using floats instead of ints or Decimals. * If someone doesn't get how to empty a list using a[:]=[], it is a good time to go through the basics of slicing which are a foundation for understanding many parts of the language. A language suitable for beginners should be easy to learn, but it should not leave them permanently crippled. All of the above are sets of training wheels that don't come off. To misquote Einstein: The language should be as simple as possible, but no simpler. /rant Raymond ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
On Feb 5, 2006, at 10:48 AM, Raymond Hettinger wrote: So I was wondering if module math (and perhaps by symmetry module cmath, too) shouldn't grow a function 'areclose' (calling it just 'close' seems likely to engender confusion, since 'close' is more often used as a verb than as an adjective; maybe some other name would work better, e.g. 'almost_equal') taking two float arguments and optional tolerances and using roughly the same specs as Numeric, e.g.: def areclose(x,y,rtol=1.e-5,atol=1.e-8): return abs(x-y)atol+rtol*abs(y) IMO, the cure is worse than the disease. It is easier to learn about the hazards of floating point equality testing than to think through the implications of tolerance testing (such as loss of transitivity) and learning how to set the right tolerance values for a given application (ones that give the right results across the entire domain of expected inputs). The areclose() function can be a dangerous crutch that temporarily glosses over the issue. Without some numerical sophistication, it would not be hard create programs that look correct and pass a few test but, in fact, contain nasty bugs (non-termination, incorrect acceptance/ rejection, etc). For those of us that already know what we're doing with floating point, areclose would be very convenient to have. Especially for unit testing. I could definitely throw away a bunch of ugly code that uses less correct arbitrary tolerance guesses if it were around. -bob ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
[Bob Ipppolito] For those of us that already know what we're doing with floating point, areclose would be very convenient to have. Do you agree that the original proposed use (helping newbs ignore floating point realities) is misguided and error-prone? Just curious, for your needs, do you want both absolute and relative checks combined into the same function? Especially for unit testing. I could definitely throw away a bunch of ugly code that uses less correct arbitrary tolerance guesses if it were around. The unittest module already has assertAlmostEqual(). Does that method meet your needs or does it need to be improved in some way? Raymond ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] math.areclose ...?
On Sun, 5 Feb 2006 13:48:51 -0500, Raymond Hettinger [EMAIL PROTECTED] wrote: [...] rant [...] A language suitable for beginners should be easy to learn, but it should not leave them permanently crippled. All of the above are sets of training wheels that don't come off. To misquote Einstein: The language should be as simple as possible, but no simpler. /rant ++1 QOTW Regards, Bengt Richter ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com