[Python-ideas] PEP 485: A Function for testing approximate equality
Ron Adam
ron3200 at gmail.com
Fri Feb 6 04:53:49 CET 2015
On 02/05/2015 06:44 PM, Steven D'Aprano wrote:
> On Thu, Feb 05, 2015 at 11:39:43AM -0800, Chris Barker wrote:
>
>>> > >- What if a tolerance is inf or nan? What if all args are inf or nan?
>> >
>> >0.0 < rel_tol < 1.0)
> I can just about see the point in restricting rel_tol to the closed
> interval 0...1, but not the open interval. Mathematically, setting the tolerance to 0
> should just degrade gracefully to exact equality, and a tolerance of
> 1 is nothing special at all.
I Agree.
> Values larger than 1 aren't often useful, but there really is no reason
> to exclude tolerances larger than 1. "Give or take 300%" (ie.
> rel_tol=3.0) is a pretty big tolerance, but it is well-defined: a
> difference of 299% is "close enough", 301% is "too far".
I agree here too.
The question I have is, is it better to get an excption, and possibly need
to wrap the isclose() in a try-except, or better to let it go above 1?
If this is used in many places, I can see wrapping it in try-excepts as a
bigger problem. The same goes for when both tolerances are zero.
> You might argue that if you want exact equality, you shouldn't use a
> tolerance at all but just use == instead. But consider a case where
> you might be trying calculations repeatedly and decreasing the tolerance
> until it fails:
>
> # doesn't handle termination properly
> rel_tol = pick_some_number
> while close_to(something, something_else, rel_tol):
> rel_tol /= 2
>
> In some cases, your calculation may actually be exact, and it simplies
> the code if close_to(a, b, rel_tol) degrades nicely to handle the exact
> case rather than you needing to switch between close_to and == by hand.
Yes.. +1
> Negative error tolerances, on the other hand, do seem to be meaningless
> and should be prevented.
No they are well behaved. It's just a measurement from the other end of
the board. ;-)
t = .1 (10 - 10 * .1, 10 + 10 * .1)
(9, 11)
t = -.1 (10 - 10 * -.1, 10 + 10 * -.1)
(11, 9)
So you get the same range either way. It works out in the isclose
calculations just fine, a negative tolerance would give the same result as
the positive of the same value.
Again, is this a place where we would want an exception, and would we need
to write it like isclose(a, b, rel_tolerance=abs(t)) any place where the
tolerance value might go negative, or would we like it to be more forgiving
and easier to use?
>> >I've enforced this in the sample code -- it's not strictly necessary, but
>> >what does a negative relative tolerance mean, anyway, and a tolerance over
>> >1.0 has some odd behaviour with zero and could hardly be called "close"
>> >anyway. Text added to make this clear.
> I don't see why a tolerance over 1 should behave any more oddly with
> zero than a tolerance under 1.
>
> And as for "close", some people would argue that rel_tol=0.5 is "hardly
> close". Sometimes you might accept anything within an order of magnitude
> the expected value: anything up to 10*x is "close enough". Or 20 times.
> Who knows?
>
> (E.g. "guess the number of grains of sand on this beach".) Any upper
> limit you put in is completely arbitrary, and this function shouldn't be
> in the business of telling people how much error they are allowed to
> tolerate. It's easy for people to put in their own restrictions, but
> hard for them to work around yours.
I agree with this idea in principle. I think weather we want to handle
exceptions or not is more of an issue though.
If it does allow higher tolerances, then it does need to handle them
correctly. I don't see that as a difficult problem though.
I prefer the weak version myself. Because if you graph the result of True
values for rel_tolerance=1. You get a graph where all like signed numbers
are close. A tolerance of .5 gives a graph of the fifty percent of middle
like signed numbers. And you can think of it as a percentage of the larger
value. Which tends to be easier than thinking about percent increase.
Also this recommends using this method.
http://c-faq.com/fp/fpequal.html
So for the weak method and increasing values of tolerance:
A graphs of all True values fill from the like signed diagonal and
converges on the unlike signed diagonal when rel_tolerance=2. Values above
that don't change anything, they are all still true. So rel_tolerance=1
gives True for all like signed numbers. And all unlike signed number is
the graph rel_tolerance=2 minus the graph of rel_tolerance=1.
For the strong method, and increasing values of tolerance:
The graphs fill from the like signed diagonal axis first until t=2, (the
like signed quadrants are not filled yet), then it also starts filling from
the unlike signed axis. So t=3 shows an X pattern, with a wider area in the
like signed quadrants. I'm not sure what the upper value of t is needed so
all values are True? It may be inf,
Keep in mind these graphs are the sum of comparing all the different values
given a particular value of t.
So it there isn't a reason to limit the range of the tolerance, it will
work just fine if we don't.
It's much harder to pick a strong tolerance that gives some sort of
specific behaviour. For that reason I prefer the weak version much more
than the strong version.
Cheers,
Ron
More information about the Python-ideas
mailing list