Python thinks Euler has identity issues (cmath returning funky results)

夙愿已清 提交于 2020-01-04 14:15:18

问题


My code:

import math
import cmath
print "E^ln(-1)", cmath.exp(cmath.log(-1))

What it prints:

E^ln(-1) (-1+1.2246467991473532E-16j)

What it should print:

-1

(For Reference, Google checking my calculation)

According to the documentation at python.org cmath.exp(x) returns e^(x), and cmath.log(x) returns ln (x), so unless I'm missing a semicolon or something , this is a pretty straightforward three line program.

When I test cmath.log(-1) it returns πi (technically 3.141592653589793j). Which is right. Euler's identity says e^(πi) = -1, yet Python says when I raise e^(πi), I get some kind of crazy talk (specifically -1+1.2246467991473532E-16j).

Why does Python hate me, and how do I appease it?

Is there a library to include to make it do math right, or a sacrifice I have to offer to van Rossum? Is this some kind of floating point precision issue perhaps?

The big problem I'm having is that the precision is off enough to have other values appear closer to 0 than actual zero in the final function (not shown), so boolean tests are worthless (i.e. if(x==0)) and so are local minimums, etc...

For example, in an iteration below:

X = 2 Y= (-2-1.4708141202500006E-15j)
X = 3 Y= -2.449293598294706E-15j
X = 4 Y= -2.204364238465236E-15j
X = 5 Y= -2.204364238465236E-15j
X = 6 Y= (-2-6.123233995736765E-16j)
X = 7 Y= -2.449293598294706E-15j

3 & 7 are both actually equal to zero, yet they appear to have the largest imaginary parts of the bunch, and 4 and 5 don't have their real parts at all.

Sorry for the tone. Very frustrated.


回答1:


The problem is inherent to representing irrational numbers (like π) in finite space as floating points.

The best you can do is filter your result and set it to zero if its value is within a given range.

>>> tolerance = 1e-15
>>> def clean_complex(c):
...   real,imag = c.real, c.imag
...   if -tolerance < real < tolerance:
...     real = 0
...   if -tolerance < imag < tolerance:
...     imag = 0
...   return complex(real,imag)
... 
>>> clean_complex( cmath.exp(cmath.log(-1)) )
(-1+0j)



回答2:


As you've already demonstrated, cmath.log(-1) doesn't return exactly i*pi. Of course, returning pi exactly is impossible as pi is an irrational number...

Now you raise e to the power of something that isn't exactly i*pi and you expect to get exactly -1. However, if cmath returned that, you would be getting an incorrect result. (After all, exp(i*pi+epsilon) shouldn't equal -1 -- Euler doesn't make that claim!).

For what it's worth, the result is very close to what you expect -- the real part is -1 with an imaginary part close to floating point precision.




回答3:


It appears to be a rounding issue. While -1+1.22460635382e-16j is not a correct value, 1.22460635382e-16j is pretty close to zero. I don't know how you could fix this but a quick and dirty way could be rounding the number to a certain number of digits after the dot ( 14 maybe ? ).

Anything less than 10^-15 is normally zero. Computer calculations have a certain error that is often in that range. Floating point representations are representations, not exact values.



来源:https://stackoverflow.com/questions/17072120/python-thinks-euler-has-identity-issues-cmath-returning-funky-results

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!