
[Om Joshi <om+python@omajoshi.com>]
I spent a couple hours putting this together: https://github.com/omajoshi/complex_math
It does lazy updating, staying in polar form until an addition, then staying in rectangular form until the next multiplication.
I implemented Tim Peters' tests (from two emails back): https://github.com/omajoshi/complex_math/blob/main/test.py
Here are my results vs his: https://github.com/omajoshi/complex_math/blob/main/test.txt
The library may be useless, but as far as I can it is associative (at least on Tim's tests).
Ya, polar is much more natural for expressing complex multiplication. The Cartesian form _can_ be made associative too, but I'm not aware of any implementation that actually does so. Proof: there are, up to isomorphism, two 4-element groups, both of which happen to be commutative. Pick either one, and name each of the 4 elements with one of the 4 complex zeroes. Then let the group's "multiplication" table _define_ the result. That's major hackery, though, and doesn't seem to follow from any "natural" way of doing 754 arithmetic on the components. Confounding it: some other results for signed zeroes are defined by various semi-authoritative sources, like Annex G of the most recent C standards. In particular, "the angle" ("phase", or "argument") of a complex number is computed by carg(z), where special cases are supposed to do the same as atan2(cimag(z), creal(z)),. Which is more arbitrary gibberish for signed zeroes: ... print(y, x, atan2(y, x)) ... 0.0 0.0 0.0 0.0 -0.0 3.141592653589793 -0.0 0.0 -0.0 -0.0 -0.0 -3.141592653589793 Which Python's cmath.phase() satisfies on my box:
cmath.phase(complex(0.0, 0.0)) 0.0 cmath.phase(complex(-0.0, 0.0)) 3.141592653589793 cmath.phase(complex(0.0, -0.0)) -0.0 cmath.phase(complex(-0.0, -0.0)) -3.141592653589793
But I don't suggest anyone spend time on this. It's a bottomless pit, and nobody cares :-)