Re: [Python-Dev] math.areclose ...?

2006-02-15 Thread Smith
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 ...?

2006-02-15 Thread Gustavo J. A. M. Carneiro
  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 ...?

2006-02-08 Thread Scott David Daniels
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 ...?

2006-02-07 Thread Smith
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 ...?

2006-02-06 Thread Aahz
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 ...?

2006-02-06 Thread Alex Martelli
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 ...?

2006-02-06 Thread Raymond Hettinger
[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-02-06 Thread Baczek
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 ...?

2006-02-06 Thread Ron Adam
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 ...?

2006-02-05 Thread Aahz
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 ...?

2006-02-05 Thread Georg Brandl
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 ...?

2006-02-05 Thread Raymond Hettinger
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 ...?

2006-02-05 Thread Bob Ippolito

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 ...?

2006-02-05 Thread Raymond Hettinger
[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 ...?

2006-02-05 Thread Bengt Richter
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