-
-
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
Fix incorrect sign of atanh(complex(x,y)) if x == -1 #31061
Conversation
In the case that x==-1, we have to flip the sign of ξ.
Co-Authored-By: cafaxo <cafaxo@gmail.com>
The |
This should have a test to prevent this from regressing. |
Should it be |
Can we also fix Most complex functions return some complex mix of |
I think we have at some point decided that throwing an appropriate error is more Julian than silently producing |
Arguably in the |
Note that julia> ccall(:catanh, ComplexF64, (ComplexF64,), complex(1.0, +0.0))
Inf + 0.7853981633974483im
julia> ccall(:catanh, ComplexF64, (ComplexF64,), complex(1.0, -0.0))
Inf - 0.7853981633974483im so that would also argue for (Python |
Note that this reference doesn't have the |
Yes, is differs in another way: It does |
We can fix
Should I add this change? |
I don't understand the rationale for the In particular, consider the following example where our current code gives quite inaccurate results: julia> atanh(1+2.98e-154im)
176.7528106982835 + 0.7853981633974483im
julia> tanh(atanh(1+2.98e-154im))
1.0 + 5.963336292480018e-154im In contrast, julia> catanh(1+2.98e-154im)
177.09966410056285 + 0.7853981633974483im
julia> tanh(catanh(1+2.98e-154im))
1.0 + 2.9799999999999177e-154im And if I simplify our function myatanh(z::Complex{T}) where T<:AbstractFloat
Ω = prevfloat(typemax(T))
θ = sqrt(Ω)/4
x, y = reim(z)
ax = abs(x)
ay = abs(y)
if ax > θ || ay > θ #Prevent overflow
if isnan(y)
if isinf(x)
return Complex(copysign(zero(x),x), y)
else
return Complex(real(1/z), y)
end
end
if isinf(y)
return Complex(copysign(zero(x),x), copysign(oftype(y,pi)/2, y))
end
return Complex(real(1/z), copysign(oftype(y,pi)/2, y))
elseif ax==1
ξ = copysign(log(sqrt(sqrt(4+y*y))/sqrt(ay)), x)
η = copysign(oftype(y,pi)/2 + atan(ay/2), y)/2
else #Normal case
ysq = ay^2
ξ = log1p(4x/((1-x)^2 + ysq))/4
η = angle(Complex((1-x)*(1+x)-ysq, 2y))/2
end
Complex(ξ, η)
end
julia> myatanh(1+2.98e-154im)
177.09966410056285 + 0.7853981633974483im
julia> tanh(myatanh(1+2.98e-154im))
1.0 + 2.9799999999999177e-154im What problem does the |
As a more minor matter, I also don't understand why we do |
@cafaxo, I agree that flipping the sign seems like a good idea. |
This seems like a minor change to everyone on triage: technically breaking, but better, so we should change it but not backport that change. Keep in mind that users of long term support versions are super conservative and want their programs to keep working as is unless the previous behavior was so horribly wrong that it couldn't be working right. |
Ok, triage might be wrong about this one. |
Can't we just use a different expansion near Our expansion near that singularity is needlessly bad, which leads to rounding causing the |
The current Julia implementation mistranscribed the reference: The multiplication with the sign of x is missing (see #31061 (comment)). This PR currently adds that multiplication, fixing both the original sign issue and the problems near |
Should this also add some tests of for |
There are a bunch of branch cut and limit tests here: Lines 684 to 730 in dfee945
so can add those there. |
I guess they were not incorrect previously then. Carry on. |
I have added tests for the cases that were fixed after replacing |
Looks like the CI failures are due to getting slightly different values here: julia/stdlib/LinearAlgebra/src/dense.jl Lines 927 to 930 in e5e1253
These should be updated with the new values. |
Thanks @cafaxo! |
It would be nice to clean up the commit message when squashing this kind of PR. The GitHub UI makes it quite easy to do—you just need to edit the message in the web interface. |
Good point, will do in future. |
A partial backport should be done! This is not about the choice of the cut, just |
* Fix incorrect sign in atanh In the case that x==-1, we have to flip the sign of ξ. * Formatting: Add space after comma Co-Authored-By: cafaxo <cafaxo@gmail.com> * Add test * Do not drop sign of zero * Flip sign to avoid a DomainError This fixes atanh(prevfloat(-1.0) + 0im) * Test all four combinations Co-Authored-By: cafaxo <cafaxo@gmail.com> * Tests for expressions that were signed incorrectly * Use the correct type for 1 * Update doc * Update doc: Remove trailing whitespace (cherry picked from commit 66341a3)
* Fix incorrect sign in atanh In the case that x==-1, we have to flip the sign of ξ. * Formatting: Add space after comma Co-Authored-By: cafaxo <cafaxo@gmail.com> * Add test * Do not drop sign of zero * Flip sign to avoid a DomainError This fixes atanh(prevfloat(-1.0) + 0im) * Test all four combinations Co-Authored-By: cafaxo <cafaxo@gmail.com> * Tests for expressions that were signed incorrectly * Use the correct type for 1 * Update doc * Update doc: Remove trailing whitespace (cherry picked from commit 66341a3)
* Fix incorrect sign in atanh In the case that x==-1, we have to flip the sign of ξ. * Formatting: Add space after comma Co-Authored-By: cafaxo <cafaxo@gmail.com> * Add test * Do not drop sign of zero * Flip sign to avoid a DomainError This fixes atanh(prevfloat(-1.0) + 0im) * Test all four combinations Co-Authored-By: cafaxo <cafaxo@gmail.com> * Tests for expressions that were signed incorrectly * Use the correct type for 1 * Update doc * Update doc: Remove trailing whitespace (cherry picked from commit 66341a3)
In the case that x==-1, we have to flip the sign of ξ. Fixes the problem noticed in #31054.
Update:
The current Julia implementation was mistranscribed from the reference: The multiplication with the sign of x is missing (see #31061 (comment)). This PR currently adds that multiplication, fixing both the original sign issue and the problems (DomainError) near
z=-1+0im
.