When I evaluate (-1)**0.5
in Python, the result is (6.123233995736766e-17+1j)
. What is this number, and how can I get just 1j
as the result?

- 47,440
- 4
- 68
- 97

- 145
- 7
-
3It's pretty close to the right answer, you must admit... – Nate Eldredge Jan 11 '21 at 05:16
-
The weird value is `math.cos(math.pi/2)`. `math.pi` is a *little* bit off from the actual mathematical π. For small errors, sin(π/2 + x) ≈ 1 and cos(π/2 + x) ≈ x, so the value you're getting is an approximation of the error in the floating point representation of π! If you `float.hex` it, you see the exponent is `-54`, because `math.pi/2` sits in the exponent `0` range and covers the first 52 bits correctly. The *reason* this value shows up is because the Python devs were too lazy to implement a "perfect" `pow` (and I can't blame them). They just threw it together from trig functions. – HTNW Jan 11 '21 at 06:01
1 Answers
6.123233995736766e-17
is a very small number expressed in scientific notation - written as a decimal, this number is 0.00000000000000006123233995736766
. The correct real part of the result should be exactly zero, so the result is wrong, but only slightly wrong. Generally, computations involving floating-point numbers do not give exact results; for an explanation, see Is floating point math broken?
If you want to compute complex square roots and guarantee that the square root of a negative real number is purely imaginary, you could write a function specifically to have this behaviour:
def my_sqrt(z):
z = complex(z)
if z.real < 0 and z.imag == 0:
return 1j * (-z.real) ** 0.5
else:
return z ** 0.5
Examples:
>>> my_sqrt(-1)
1j
>>> my_sqrt(-2)
1.4142135623730951j
>>> my_sqrt(9)
(3+0j)
>>> my_sqrt(-3 + 4j)
(1.0000000000000002+2j)
Note that due to floating-point inaccuracies, some results will be slightly wrong, for example the true square root of -3 + 4j
should be 1 + 2j
. If you want exact results in all circumstances where this is possible, consider learning SymPy.

- 47,440
- 4
- 68
- 97
-
Or they could use [`cmath.sqrt`](https://docs.python.org/3/library/cmath.html#cmath.sqrt), which even gets your last example right. – Kelly Bundy Jan 11 '21 at 08:16
-
@KellyBundy `cmath.sqrt` happens to get the last example right, but there are other examples such as `cmath.sqrt(-7.79 + 6.6j)` which is `(1.0999999999999999+3j)` when the exact result is `1.1 + 3j`. That said, I wasn't aware, but it does appear to give pure-imaginary results for negative real numbers. The documentation doesn't say this is guaranteed, but I wasn't able to find any counterexamples. – kaya3 Jan 11 '21 at 08:32
-
I disagree that the correct result of your example is exactly-representable. Your squaring introduces new inaccuracy, so the correct result of then taking the root is *not* exactly `0.11 + 0.3j`. – Kelly Bundy Jan 11 '21 at 08:40
-
Anybody doing mathematics is not going to change their definition of "correct" to account for inaccuracies introduced by the computer. If inaccuracies are introduced by the computer, then the result is definitively not exactly correct, regardless of the reason they are introduced. The point I am making is that floating-point calculations cannot give exact results in all circumstances; at most we can say that `cmath.sqrt` gives exact results in more circumstances. SymPy is still the way to go if exact results are required. – kaya3 Jan 11 '21 at 08:49
-
Well my point is just that it looked like you blamed `cmath.sqrt` for the inaccuracy. Rather than the floats it receives (as a complex). It might actually be giving us the most accurate result for the inaccurate input it gets. Given that neither -7.79 nor 6.6 are represented exactly, I'm not convinced that `1.1` is closer to the exact value than `1.0999999999999999` is. – Kelly Bundy Jan 11 '21 at 10:33
-
Yes, apologies that my wording was poor. What I mean is that from a mathematician's perspective, if you input `-7.79 + 6.6j` on the keyboard and the output on the screen isn't exactly `1.1 + 3j` then it's not an exact result. From a programmer's perspective, `cmath.sqrt` does seem overall better than my solution, except for the issue that the docs/specification doesn't guarantee the desired behaviour, whereas if you write your own function to have a particular behaviour then you can guarantee it. – kaya3 Jan 11 '21 at 17:39