unittest: Proposal to add failUnlessNear

J

John Roth

Christopher T King said:
Why would you have to do that? The Python operators, as well as every
function in cmath, transparently support both floats and complex numbers
(as they should). Every operation between floats and complex numbers is
well-defined.

Because the "distance" between two floats is

abs(a - b)

while the "distance" between two complex numbers

is something like

math.sqrt(diff.real ** 2 + diff.imag ** 2)

This requires a type check to differentiate which
formula you need to use.

John Roth
 
T

Tim Peters

[John Roth]
[Christopher T King]
Why would you have to do that? The Python operators, as well as every
function in cmath, transparently support both floats and complex numbers
(as they should). Every operation between floats and complex numbers is
well-defined.
[John]
Because the "distance" between two floats is

abs(a - b)

while the "distance" between two complex numbers

is something like

math.sqrt(diff.real ** 2 + diff.imag ** 2)

This requires a type check to differentiate which
formula you need to use.

Nope. abs(a - b) works for both cases, although for complex numbers
Python uses a numerical method less prone to spurious
overflow/underflow than the "square root of the sum of the squares"
formula.

which = sqrt((12-9)**2 + (29-25)**2) = sqrt(3**2 + 4**2) = sqrt(9 +
16) = sqrt(25).

Note that if the difference in the imaginary components is 0, the
formula reduces to

math.sqrt(diff.real**2)

which = |diff.real|. IOW, the definition of real abs() is a special
case of the definition of complex abs().
 
J

John Roth

Nope. abs(a - b) works for both cases, although for complex numbers
Python uses a numerical method less prone to spurious
overflow/underflow than the "square root of the sum of the squares"
formula.

I didn't know that. It does make sense to do something like
that, but it seems a bit like deep magic to make abs
recognize that the operand is a subtraction.

John Roth
 
T

Tim Peters

[Tim Peters]
[John Roth]
I didn't know that. It does make sense to do something like
that, but it seems a bit like deep magic to make abs
recognize that the operand is a subtraction.

That would be deep magic indeed! But that doesn't happen. abs(x)
works on "a number". Regardless of whether a and b are float or
complex or integer or a mix, abs(a-b) first subtracts b from a, then
passes the difference to abs().
 
J

John Roth

Tim Peters said:
[Tim Peters]
[John Roth]
I didn't know that. It does make sense to do something like
that, but it seems a bit like deep magic to make abs
recognize that the operand is a subtraction.

That would be deep magic indeed! But that doesn't happen. abs(x)
works on "a number". Regardless of whether a and b are float or
complex or integer or a mix, abs(a-b) first subtracts b from a, then
passes the difference to abs().

Is that how complex subtraction works? I thought it produced
a complex, and your answers seem to say it produces a real.
Obviously, my mathematical background isn't giving me the
same answers it's giving you.

John Roth
 
P

Peter Otten

[John Roth trying hard to confuse himself :)]

Here's another perspective: abs(x) is ignorant of the class of x. Like
len(), it just calls the corresponding special method which does the
appropriate thing -- max(x, -x) for float, sqrt(x.real**2 + x.imag**2) for
complex -- or something theoretically equivalent, but better suited to the
limitations of numerical mathematics.
.... def __abs__(self):
.... return self.upper()
....
Peter
 
R

Roy Smith

John Roth said:
Because the "distance" between two floats is

abs(a - b)

while the "distance" between two complex numbers

is something like

math.sqrt(diff.real ** 2 + diff.imag ** 2)

The distance between two complex numbers is indeed computed using the
pythagorean formula, but all that is hidden from view when you just say
"abs (a - b)".
4.4721359549995796
 
R

Roy Smith

"John Roth said:
I didn't know that. It does make sense to do something like
that, but it seems a bit like deep magic to make abs
recognize that the operand is a subtraction.

John Roth

It's not deep magic at all. It's just the normal rules of complex math.
 
T

Tim Peters

[John Roth]
Is that how complex subtraction works? I thought it produced
a complex,

That's right.
and your answers seem to say it produces a real.

No, complex.__abs__() produces a float. Every type is free to
implement __abs__ in any way it likes. complex.__abs__ is implemented
as if by

class complex:
...
def __abs__(self):
import math
return math.hypot(self.real, self.imag)

In the same way, every type is free to implement __sub__ in any way it
likes, which is why infix "-" can also do a different thing for
complex operands than for float operands.

BTW, abs() itself is implemented as if by

def abs(x):
return x.__abs__()
 
A

Antoon Pardon

Floats are not a subset of complex. I concur
with Roy Smith's comments on that issue. There's

Yes they are.
no reason why complex numbers cannot be
represented by a pair of integers, or rationals,
or the new floating decimal type, or whatever.

I think this is getting sidetracked. This started
with a request for a better test to check whether
something is near enough something else. Since
all your alternatives give exact results you don't
need to test for nearness you test for equality.

So within this contexts where you can't calculate
things exactly floats are a subset of complex.
In addition, you're going to have to do significant
type checking if you want to combine floats and
complex in the same method call. That's just
poor design.

No you don't. Please explain why something like

abs(a - b) < tolerance

needs typechecking when a and b can be complex
numbers as well as floats
I take it you've never worked with FIT. It's intended
to be used by non-technical people on a project, such
as the on-site customer, business analysts and so forth.
If I did something as silly as requiring them to insert
a tolerance that is blatently obvious to anyone looking
at the number involved, I'd get a change request so fast
that the edges would char from the friction.

A tolerance is never blatantly obvious from looking
at the number involved. On a number like 6.23e14
the tolreance could be 5e11 or 3e12 in fact from
just looking at the number I would guess at a tolerace
of 1e12, in other words bounds between 6.22e14 and
6.24e14.

Besides you are mixing user interface and implementation.
There is nothing stopping you from inferring this obvious
tolerance and using it in your program. The fact that
the user just insered 6.23e14, doesn't stop you the
programmer to test whether a second number lies within
a fault tolerance of 5e11 of 6.23e14
 
A

Antoon Pardon

Because the "distance" between two floats is
abs(a - b)
while the "distance" between two complex numbers
is something like

is just the same: abs(a - b) it works for complex numbers
just as well as it does with floats. In fact it works for
any numberlike object that has __sub__ and __abs__ methods
defined.
math.sqrt(diff.real ** 2 + diff.imag ** 2)

This is just the definition for abs on complex numbers.
This requires a type check to differentiate which
formula you need to use.

No it doesn't.
 
A

Antoon Pardon

For one blatently obvious reason. It's harder
to calculate that in the character form than it
is to insert the '5', and you don't have the
information to tell what you wanted if you
convert from character to float first.

And by making it easier here you make it more
difficult for yourself later on because now
you need two different ways to see whether
two numbers are near enough depending on
whether you are working with floats or complex
numbers.
My objective here is to ***not have to***
separately enter a precision. The semantics
of saying I want something to be treated as equal
if it's "close enough" to 6.23e14 is that it should
be closer to that than to either 6.24e14 or
6.22e14.

But you don't follow this same procedure with complex
numbers. If you are working with complex numbers you
are prepared to check whether a number is within a
certain distance from another number. if you have

6.23e14 + 3.49e11j you can work with the same procedure
and test that your second number is within the rectangle
that lies between 6.235e14 and 6.225e14 on the real
axis and between 3.485j and 3.495j on the imaganary axis.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top