Re: Comparing floats

2010-11-29 Thread Marco Nawijn
On 29 nov, 00:20, Nobody  wrote:
> On Sat, 27 Nov 2010 18:23:48 -0500, Terry Reedy wrote:
> >> Therefore, to implement this multiplication operation I need to have a
> >> way to verify that the float tuples C and D are "equal".
>
> > I might try the average relative difference:
> > sum(abs((i-j)/(i+j)) for i,j in zip(C,D))/n # assuming lengths constant
>
> The division is unstable if i and j are close to zero.
>
> For scalars, I'd use:
>
>         abs(i-j) <= epsilon * (1 + abs(i+j))
>
> This amounts to a relative error check for large values and an absolute
> error check for values close to zero.
>
> For a vector, I'd check that the above holds for all pairs.

Hi All,

Why don't you treat the C and D tuples as vectors? You can than check
dot product
and norm (length) for equality. Using scipy (www.scipy.org), you even
get very nice
performance.

Marco
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparing floats

2010-11-28 Thread Nobody
On Sat, 27 Nov 2010 18:23:48 -0500, Terry Reedy wrote:

>> Therefore, to implement this multiplication operation I need to have a
>> way to verify that the float tuples C and D are "equal".
> 
> I might try the average relative difference:
> sum(abs((i-j)/(i+j)) for i,j in zip(C,D))/n # assuming lengths constant

The division is unstable if i and j are close to zero.

For scalars, I'd use:

abs(i-j) <= epsilon * (1 + abs(i+j))

This amounts to a relative error check for large values and an absolute
error check for values close to zero.

For a vector, I'd check that the above holds for all pairs.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparing floats

2010-11-28 Thread Peter Otten
kj wrote:

> I understand that, in Python 2.7 and 3.x >= 3.1, when the interactive
> shell displays a float it shows "the shortest decimal fraction that
> rounds correctly back to the true binary value".  Is there a way
> to access this rounding functionality from code that must be able
> to run under version 2.6? (The idea would be to implement float
> comparison as a comparison of the rounded versions of floats.)

Doesn't float(str(x)) == x for all x imply that str(x) == str(y) if and only 
if x == y? If so, what would be the benefit of converting to string at all?

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparing floats

2010-11-27 Thread Steven D'Aprano
On Sat, 27 Nov 2010 22:55:10 +, kj wrote:

[...]
> Therefore, to implement this multiplication operation I need to have a
> way to verify that the float tuples C and D are "equal". 

That C and D are tuples of floats is irrelevant. The problem boils down 
to testing floats for equality.

It's easy to test two floats for equality, that's exactly what == does, 
but two floats which should be equal might not be due to calculation 
errors. To work around this, we loosen the definition of "equal" to give 
some allowance for rounding errors. Unfortunately, you need to decide 
what you mean by "two floats are equal", since that will depend on the 
semantics of your problem and data. There is no standard answer that 
applies everywhere.

I suggest you leave it up to the user to decide what tolerance their data 
can support, and offer a sensible default for cases that they don't know 
or don't care.

This might be useful for you, or at least give you some ideas:

http://code.activestate.com/recipes/577124-approximately-equal/



[...]
> The only approach I know of is to pick some arbitrary tolerance epsilon
> (e.g. 1e-6) and declare floats x and y equal iff the absolute value of x
> - y is less than epsilon.

The four basic approaches are:

(1) Is the absolute difference between the values <= some tolerance?
(2) Is the relative difference between the values <= some tolerance?
(3) Round the two values to a fixed number of decimal places, then 
compare for equality. This is a variation on (1) above.
(4) How many differences in the least significant bits of the two values 
do we accept?



> I understand that, in Python 2.7 and 3.x >= 3.1, when the interactive
> shell displays a float it shows "the shortest decimal fraction that
> rounds correctly back to the true binary value".  Is there a way to
> access this rounding functionality from code that must be able to run
> under version 2.6? (The idea would be to implement float comparison as a
> comparison of the rounded versions of floats.)

How do you expect to access code in the Python 2.7 interpreter from 
Python 2.6? If you have 2.7 available, just use 2.7 :)

It is a standard, royalty-free algorithm that you can find on the 
Internet somewhere. Worst case, you could copy it from the Python 2.7 
source code, re-write it in Python if need be, and distribute it in your 
own application. But I don't think it will help you, since it isn't 
dealing with the fundamental problem that:

* equality between two floats is well-defined, but not useful

* equality given some tolerance is useful, but not well-defined (there is 
no tolerance that is always best, and there is no general way to decide 
whether absolute or relative error is more important)



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparing floats

2010-11-27 Thread Arnaud Delobelle
Terry Reedy  writes:

> On 11/27/2010 5:55 PM, kj wrote:
>
>> Therefore, to implement this multiplication operation I need to
>> have a way to verify that the float tuples C and D are "equal".
>
> I might try the average relative difference:
> sum(abs((i-j)/(i+j)) for i,j in zip(C,D))/n # assuming lengths constant

That'll throw an exception if i == -j.  You could replace (i+j) with
math.hypot(i, j) or abs(i)+abs(j) but it will still fail when i == j ==
0.

-- 
Arnaud

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparing floats

2010-11-27 Thread Terry Reedy

On 11/27/2010 5:55 PM, kj wrote:


Therefore, to implement this multiplication operation I need to
have a way to verify that the float tuples C and D are "equal".


I might try the average relative difference:
sum(abs((i-j)/(i+j)) for i,j in zip(C,D))/n # assuming lengths constant


Certainly, I want to do this in in a way that takes into account
the fact machine computations with floats can produce small
differences between numbers that are notionally the same.


The problem is that the appropriate value may depend on the application 
and the source of the floats. If they are measured to 3 decimal places, 
you need a large value. If they are calculated, you need much smaller.


--
Terry Jan Reedy

--
http://mail.python.org/mailman/listinfo/python-list


Comparing floats

2010-11-27 Thread kj



I'm defining a class (Spam) of objects that are characterized by
three parameters, A, B, C, where A and C are n-tuples of floats
and B is an n*n tuple-of-tuples of floats.  I'm defining a limited
multiplication for these objects, like this:

Spam(A, B, C) * Spam(D, E, F) = Spam(A, dot(B, E), F)
  if and only if C == D.

(Here dot(B, E) represents the matrix multiplication of B and E).

In other words, this multiplication is defined only for the case
where the last parameter of the first object is equal to first
parameter of the second object.  An exception should be thrown if
one attempts to multiply two objects that fail to meet this
requirement.

Therefore, to implement this multiplication operation I need to
have a way to verify that the float tuples C and D are "equal".
Certainly, I want to do this in in a way that takes into account
the fact machine computations with floats can produce small
differences between numbers that are notionally the same.  E.g.
(in Python 2.6.1 at least):

>>> 49.0 * (1.0/49.0)
0.99989
>>> 1.0 == 49.0 * (1.0/49.0)
False

The only approach I know of is to pick some arbitrary tolerance
epsilon (e.g. 1e-6) and declare floats x and y equal iff the absolute
value of x - y is less than epsilon.

Does the Python standard library provide any better methods for
performing such comparisons?

I understand that, in Python 2.7 and 3.x >= 3.1, when the interactive
shell displays a float it shows "the shortest decimal fraction that
rounds correctly back to the true binary value".  Is there a way
to access this rounding functionality from code that must be able
to run under version 2.6? (The idea would be to implement float
comparison as a comparison of the rounded versions of floats.)

Absent these possibilities, does Python provide any standard value
of epsilon for this purpose?

TIA!

~kj
-- 
http://mail.python.org/mailman/listinfo/python-list