-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
conj(sqrt(complex(-5,0))) is not the same as sqrt(conj(complex(-5,0))) #2843
Comments
This is not necessarily a bug, but rather the reflection of some choice of branch cut embedded in the complex sqrt function. It is easy to verify that the two different answers correspond to different square roots of -5. julia>x= conj(sqrt(complex(-5,-0)))
0.0 - 2.23606797749979im
julia> conj(x^2)
-5.000000000000001 + 0.0im
julia> conj(x)^2
-5.000000000000001 + 0.0im
julia>x= sqrt(conj(complex(-5,-0)))
0.0 + 2.23606797749979im
julia> conj(x)^2
-5.000000000000001 - 0.0im
julia> conj(x^2)
-5.000000000000001 - 0.0im |
According to Kahan: http://people.freebsd.org/~das/kahan86branch.pdf |
Yes, they are different square roots of -5. I am not sure if the branch cut we have chosen is by design. I have changed the label to a decision rather than a bug. |
Should
|
Yes, that is clearly an error. The Kahan article blames this as the root cause, which would in effect determine the behavior at branch cuts. |
FWIW the first link you provide clearly favors the ISO C99 standard. Here is what it has to say on this topic (emph. mine):
|
julia> 0==-0
true
julia> bits(0)
"0000000000000000000000000000000000000000000000000000000000000000"
julia> bits(-0)
"0000000000000000000000000000000000000000000000000000000000000000"
julia> bits(-0.0e0)
"1000000000000000000000000000000000000000000000000000000000000000"
julia> bits(0.0e0)
"0000000000000000000000000000000000000000000000000000000000000000"
julia> 0.0e0 == -0.0e0
true Erm. |
Literal |
Oh, right, duh. |
Ah, so part of my confusion is that julia> conj(complex(5.0, -0.0))
5.0 + 0.0im
julia> conj(complex(5.0, +0.0))
5.0 - 0.0im
julia> conj(sqrt(complex(-5,+0)))
0.0 - 2.23606797749979im
julia> conj(sqrt(complex(-5,-0)))
0.0 - 2.23606797749979im
julia> conj(sqrt(complex(-5.0e0,-0.0e0)))
0.0 - 2.23606797749979im
julia> sqrt(conj(complex(-5.0e0,-0.0e0)))
0.0 + 2.23606797749979im
julia> sqrt(conj(complex(-5.0e0,+0.0e0)))
0.0 + 2.23606797749979im
julia> conj(sqrt(complex(-5.0e0,+0.0e0)))
0.0 - 2.23606797749979im |
There seem to two problems as @jiahao points out. There is a branch cut issue for the complex julia> conj(log(complex(-5.,-0.)))
1.6094379124341003 + 3.141592653589793im
julia> log(conj(complex(-5.,-0.)))
1.6094379124341003 + 3.141592653589793im The second problems is how to deal with |
This behavior makes sense then from a complex analysis standpoint. The Riemann surface of complex log is well-behaved except at complex 0, where the branch cuts serve to chop up the Riemann surface into single-valued domains, whereas the square root has nontrivial singularities at the branch cut which require a decision to be made about which surface to follow at the branch cut. |
Going back and reading the ISO C99 standard, it seems clear to me that the behavior we see conforms to the branch cut decisions made in the standard. |
I don't think it is matching up to the C99 standard for floats: julia> sqrt(complex(-1.0,-0.0))
0.0 + 1.0im
julia> sqrt(complex(-1.0,-1e-100))
5.0e-101 - 1.0im |
I think there is a comparison in there where there should be a |
Fixed in d3c66e9. |
Currently in d3c66e9: julia> sqrt(conj(complex(-5.0,-0.0)))
0.0 + 2.23606797749979im
julia> sqrt(conj(complex(-5.0,0.0)))
0.0 - 2.23606797749979im
julia> conj(sqrt(complex(-5,-0)))
0.0 - 2.23606797749979im
julia> conj(sqrt(complex(-5,0)))
0.0 - 2.23606797749979im |
Is that good or bad? Note that since there's isn't a |
The behavior @simonbyrne pointed out now appears to conform to the C99 standard. Case 1: signed zeros, sqrt(x+0.0_im) is positive imaginary, sqrt(x-0.0_im) is negative imaginary. julia> sqrt(complex(-1.0,+0.0))
0.0 + 1.0im
julia> sqrt(complex(-1.0,+1e-100))
5.0e-101 + 1.0im
julia> sqrt(complex(-1.0,-0.0))
0.0 - 1.0im
julia> sqrt(complex(-1.0,-1e-100))
5.0e-101 - 1.0im Case 2: no signed zeros, sqrt(x+0*im) is positive imaginary. julia> sqrt(complex(-1,0))
0.0 + 1.0im Since |
I missed all the action here after filing. With #2845, we should hopefully be able to visit all the branch cuts and be compliant with C99. One less reason for William Kahan to be unhappy with us now. :-) |
An example from page 15 of http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf
This is also the case with
log
:Octave gives the same result in both cases.
The text was updated successfully, but these errors were encountered: