-
-
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
inaccuracy: Complex ^ Int #3246
Comments
Probably limited by the precision of |
It looks like the difference is the result of the accuracy of sin(x) for values of x close to n*pi. For small x, sin(x) \approx x. The sine function seems to handle this case, but not for sin(pi - x), which is also \approx x for small x. Compare
For negative real value and small complex component, atan2 returns an angle close to pi, resulting in the precision loss at complex.jl#L253. |
|
Ah, yes the precision loss is due to the fact that |
Sorry, I'm going off on a tangent, but has the following been reported somewhere?:
|
How about this as a crazy solution: import Base.convert, Base.show, Base.sin, Base.cos
# define a type that is equivalent to angle + quad * pi/2
type AngleQuad
angle::Float64
quad::Int
end
convert(::Type{Float64},a::AngleQuad) = a.angle + a.quad*pi*0.5
show(io::IO,a::AngleQuad) = print(io,a.angle," + ",a.quad,"π/2")
# atan2 for AngleQuads
function atan2q(y,x)
if abs(x) > abs(y)
AngleQuad(atan2(copysign(y,x),abs(x)), 2*signbit(x))
else
AngleQuad(atan2(-copysign(x,y),abs(y)), 2*signbit(y)-1)
end
end
# more accurate sin/cos
function sin(a::AngleQuad)
r = mod(a.quad,4)
if r == 0
return sin(a.angle)
elseif r == 1
return cos(a.angle)
elseif r == 2
return -sin(a.angle)
else
return -cos(a.angle)
end
end
function cos(a::AngleQuad)
r = mod(a.quad,4)
if r == 0
return cos(a.angle)
elseif r == 1
return -sin(a.angle)
elseif r == 2
return -cos(a.angle)
else
return sin(a.angle)
end
end Then we have: julia> x = atan2q(1e-20,-2)
-5.0e-21 + 2π/2
julia> sin(x)
5.0e-21 |
Could we re-open this issue, because 9470bb2 has introduced some new problems, for example:
In the previous build, these examples worked. Then, there are also some type stability issues:
Here one would probably want Complex{Int} as return type, analogously to As far as I understand the new complex ^, there are three available solutions now:
It seems some care is needed here to decide which argument types to send to which algorithm, but I think it makes sense just to immediately send Complex^Integer to the power_by squaring solution. I tried the following:
This fixes the three examples above:
|
Also, I noticed julia> complex(-2.0,1e-20)^complex(2.0,1e-20)
4.0 - 9.797174393178826e-16im We might be able to avoid that with some |
Matlab gives the same answer we do for |
Yes, that is my guess too. I have observed that in both languages we also get the same bad result when using the
|
also a fix to Rational->Int conversion
So if we adopt @simonbyrne's clever |
It is cool, but we have to consider how it integrates with the rest of the system. It's essentially a full new numeric type. |
@aswart found another complex function that causes problems for complex-step differentiation (see also #2889).
When raising a complex number with negative real part and small imaginary part to an integer power (an everyday occurrence with complex step diferentiation), the imaginary part is wrong.
Example:
This gives an accurate result :
But, when using
^(z::Complex, n::Integer) = z^complex(n)
then we get something entirely different. (MATLAB and Python give -4.0e-20).
One way to fix this would be to simply defer this case to
Base.power_by_squaring(A,p)
, but the more general case ^(Complex,Complex) would then probably still need some attention.CC: @jiahao
The text was updated successfully, but these errors were encountered: