Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Format of complex number in Python

Tags:

I am wondering about the way Python (3.3.0) prints complex numbers. I am looking for an explanation, not a way to change the print.

Example:

>>> complex(1,1)-complex(1,1)
0j

Why doesn't it just print "0"? My guess is: to keep the output of type complex.

Next example:

>>> complex(0,1)*-1
(-0-1j)

Well, a simple "-1j" or "(-1j)" would have done. And why "-0"?? Isn't that the same as +0? It doesn't seem to be a rounding problem:

>>> (complex(0,1)*-1).real == 0.0
True

And when the imaginary part gets positive, the -0 vanishes:

>>> complex(0,1)
1j
>>> complex(0,1)*-1
(-0-1j)
>>> complex(0,1)*-1*-1
1j

Yet another example:

>>> complex(0,1)*complex(0,1)*-1
(1-0j)
>>> complex(0,1)*complex(0,1)*-1*-1
(-1+0j)
>>> (complex(0,1)*complex(0,1)*-1).imag
-0.0

Am I missing something here?

like image 441
cxxl Avatar asked Nov 14 '12 21:11

cxxl


People also ask

What is complex () in Python?

Definition and Usage. The complex() function returns a complex number by specifying a real number and an imaginary number.

What is the data type of complex number in Python?

A complex number is a Python number type made of real and imaginary parts. It is represented as a+bj.

How does Python handle complex numbers?

Since complex is a native data type in Python, you can plug complex numbers into arithmetic expressions and call many of the built-in functions on them. More advanced functions for complex numbers are defined in the cmath module, which is part of the standard library.

What is number format in Python?

0 - It is the character that is placed in place of the empty spaces. 9 - It is the width option that sets the minimum width of the number to 9 (including decimal point, thousands comma and sign) . 3 - It is the precision operator that sets the precision of the given floating number to 3 places.


2 Answers

It prints 0j to indicate that it's still a complex value. You can also type it back in that way:

>>> 0j
0j

The rest is probably the result of the magic of IEEE 754 floating point representation, which makes a distinction between 0 and -0, the so-called signed zero. Basically, there's a single bit that says whether the number is positive or negative, regardless of whether the number happens to be zero. This explains why 1j * -1 gives something with a negative zero real part: the positive zero got multiplied by -1.

-0 is required by the standard to compare equal to +0, which explains why (1j * -1).real == 0.0 still holds.

The reason that Python still decides to print the -0, is that in the complex world these make a difference for branch cuts, for instance in the phase function:

>>> phase(complex(-1.0, 0.0))
3.141592653589793
>>> phase(complex(-1.0, -0.0))
-3.141592653589793

This is about the imaginary part, not the real part, but it's easy to imagine situations where the sign of the real part would make a similar difference.

like image 70
Thomas Avatar answered Sep 24 '22 12:09

Thomas


The answer lies in the Python source code itself.

I'll work with one of your examples. Let

a = complex(0,1)
b = complex(-1, 0)

When you doa*b you're calling this function:

real_part = a.real*b.real - a.imag*b.imag
imag_part = a.real*b.imag + a.imag*b.real

And if you do that in the python interpreter, you'll get

>>> real_part
-0.0
>>> imag_part
-1.0

From IEEE754, you're getting a negative zero, and since that's not +0, you get the parens and the real part when printing it.

if (v->cval.real == 0. && copysign(1.0, v->cval.real)==1.0) {
    /* Real part is +0: just output the imaginary part and do not
       include parens. */
...
else {
    /* Format imaginary part with sign, real part without. Include
       parens in the result. */
...

I guess (but I don't know for sure) that the rationale comes from the importance of that sign when calculating with elementary complex functions (there's a reference for this in the wikipedia article on signed zero).

like image 31
jorgeca Avatar answered Sep 23 '22 12:09

jorgeca