@@ -648,98 +648,89 @@ end
648
648
exp10 (z:: Complex ) = exp10 (float (z))
649
649
650
650
# _cpow helper function to avoid method ambiguity with ^(::Complex,::Real)
651
- function _cpow (z:: Complex{T} , p:: Union{T,Complex{T}} ):: Complex{T} where T<: AbstractFloat
652
- if p == 2 # square
653
- zr, zi = reim (z)
654
- x = (zr- zi)* (zr+ zi)
655
- y = 2 * zr* zi
656
- if isnan (x)
657
- if isinf (y)
658
- x = copysign (zero (T),zr)
659
- elseif isinf (zi)
660
- x = convert (T,- Inf )
661
- elseif isinf (zr)
662
- x = convert (T,Inf )
651
+ function _cpow (z:: Union{T,Complex{T}} , p:: Union{T,Complex{T}} ) where {T<: AbstractFloat }
652
+ if isreal (p)
653
+ pᵣ = real (p)
654
+ if isinteger (pᵣ) && abs (pᵣ) < typemax (Int32)
655
+ # |p| < typemax(Int32) serves two purposes: it prevents overflow
656
+ # when converting p to Int, and it also turns out to be roughly
657
+ # the crossover point for exp(p*log(z)) or similar to be faster.
658
+ if iszero (pᵣ) # fix signs of imaginary part for z^0
659
+ zer = flipsign (copysign (zero (T),pᵣ), imag (z))
660
+ return Complex (one (T), zer)
663
661
end
664
- elseif isnan (y) && isinf (x)
665
- y = copysign (zero (T), y)
666
- end
667
- Complex (x,y)
668
- elseif z!= 0
669
- if p!= 0 && isinteger (p)
670
- rp = real (p)
671
- if rp < 0
672
- return power_by_squaring (inv (z), convert (Integer, - rp))
673
- else
674
- return power_by_squaring (z, convert (Integer, rp))
675
- end
676
- end
677
- exp (p* log (z))
678
- elseif p!= 0 # 0^p
679
- zero (z) # CHECK SIGNS
680
- else # 0^0
681
- zer = copysign (zero (T),real (p))* copysign (zero (T),imag (z))
682
- Complex (one (T), zer)
683
- end
684
- end
685
- function _cpow (z:: Complex{T} , p:: Union{T,Complex{T}} ) where T<: Real
686
- if isinteger (p)
687
- rp = real (p)
688
- if rp < 0
689
- return power_by_squaring (inv (float (z)), convert (Integer, - rp))
690
- else
691
- return power_by_squaring (float (z), convert (Integer, rp))
692
- end
693
- end
694
- pr, pim = reim (p)
695
- zr, zi = reim (z)
696
- r = abs (z)
697
- rp = r^ pr
698
- theta = atan2 (zi, zr)
699
- ntheta = pr* theta
700
- if pim != 0 && r != 0
701
- rp = rp* exp (- pim* theta)
702
- ntheta = ntheta + pim* log (r)
703
- end
704
- sinntheta, cosntheta = sincos (ntheta)
705
- re, im = rp* cosntheta, rp* sinntheta
706
- if isinf (rp)
707
- if isnan (re)
708
- re = copysign (zero (re), cosntheta)
709
- end
710
- if isnan (im)
711
- im = copysign (zero (im), sinntheta)
712
- end
713
- end
714
-
715
- # apply some corrections to force known zeros
716
- if pim == 0
717
- if isinteger (pr)
718
- if zi == 0
719
- im = copysign (zero (im), im)
720
- elseif zr == 0
721
- if isinteger (0.5 * pr) # pr is even
722
- im = copysign (zero (im), im)
662
+ ip = convert (Int, pᵣ)
663
+ if isreal (z)
664
+ zᵣ = real (z)
665
+ if ip < 0
666
+ iszero (z) && return Complex (T (NaN ),T (NaN ))
667
+ re = power_by_squaring (inv (zᵣ), - ip)
668
+ im = - imag (z)
723
669
else
724
- re = copysign (zero (re), re)
670
+ re = power_by_squaring (zᵣ, ip)
671
+ im = imag (z)
725
672
end
673
+ # slightly tricky to get the correct sign of zero imag. part
674
+ return Complex (re, ifelse (iseven (ip) & signbit (zᵣ), - im, im))
675
+ else
676
+ return ip < 0 ? power_by_squaring (inv (z), - ip) : power_by_squaring (z, ip)
726
677
end
727
- else
728
- dr = pr* 2
729
- if isinteger (dr) && zi == 0
730
- if zr < 0
731
- re = copysign (zero (re), re)
678
+ elseif isreal (z)
679
+ # (note: if both z and p are complex with ±0.0 imaginary parts,
680
+ # the sign of the ±0.0 imaginary part of the result is ambiguous)
681
+ if iszero (real (z))
682
+ return pᵣ > 0 ? complex (z) : Complex (T (NaN ),T (NaN )) # 0 or NaN+NaN*im
683
+ elseif real (z) > 0
684
+ return Complex (real (z)^ pᵣ, z isa Real ? ifelse (real (z) < 1 , - imag (p), imag (p)) : flipsign (imag (z), pᵣ))
685
+ else
686
+ zᵣ = real (z)
687
+ rᵖ = (- zᵣ)^ pᵣ
688
+ if isfinite (pᵣ)
689
+ # figuring out the sign of 0.0 when p is a complex number
690
+ # with zero imaginary part and integer/2 real part could be
691
+ # improved here, but it's not clear if it's worth it…
692
+ return rᵖ * complex (cospi (pᵣ), flipsign (sinpi (pᵣ),imag (z)))
732
693
else
733
- im = copysign (zero (im), im)
694
+ iszero (rᵖ) && return zero (Complex{T}) # no way to get correct signs of 0.0
695
+ return Complex (T (NaN ),T (NaN )) # non-finite phase angle or NaN input
734
696
end
735
697
end
698
+ else
699
+ rᵖ = abs (z)^ pᵣ
700
+ ϕ = pᵣ* angle (z)
736
701
end
702
+ elseif isreal (z)
703
+ iszero (z) && return real (p) > 0 ? complex (z) : Complex (T (NaN ),T (NaN )) # 0 or NaN+NaN*im
704
+ zᵣ = real (z)
705
+ pᵣ, pᵢ = reim (p)
706
+ if zᵣ > 0
707
+ rᵖ = zᵣ^ pᵣ
708
+ ϕ = pᵢ* log (zᵣ)
709
+ else
710
+ r = - zᵣ
711
+ θ = copysign (T (π),imag (z))
712
+ rᵖ = r^ pᵣ * exp (- pᵢ* θ)
713
+ ϕ = pᵣ* θ + pᵢ* log (r)
714
+ end
715
+ else
716
+ pᵣ, pᵢ = reim (p)
717
+ r = abs (z)
718
+ θ = angle (z)
719
+ rᵖ = r^ pᵣ * exp (- pᵢ* θ)
720
+ ϕ = pᵣ* θ + pᵢ* log (r)
737
721
end
738
722
739
- Complex (re, im)
723
+ if isfinite (ϕ)
724
+ return rᵖ * cis (ϕ)
725
+ else
726
+ iszero (rᵖ) && return zero (Complex{T}) # no way to get correct signs of 0.0
727
+ return Complex (T (NaN ),T (NaN )) # non-finite phase angle or NaN input
728
+ end
740
729
end
730
+ _cpow (z, p) = _cpow (float (z), float (p))
741
731
^ (z:: Complex{T} , p:: Complex{T} ) where T<: Real = _cpow (z, p)
742
732
^ (z:: Complex{T} , p:: T ) where T<: Real = _cpow (z, p)
733
+ ^ (z:: T , p:: Complex{T} ) where T<: Real = _cpow (z, p)
743
734
744
735
^ (z:: Complex , n:: Bool ) = n ? z : one (z)
745
736
^ (z:: Complex , n:: Integer ) = z^ Complex (n)
@@ -755,6 +746,10 @@ function ^(z::Complex{T}, p::S) where {T<:Real,S<:Real}
755
746
P = promote_type (T,S)
756
747
return Complex {P} (z) ^ P (p)
757
748
end
749
+ function ^ (z:: T , p:: Complex{S} ) where {T<: Real ,S<: Real }
750
+ P = promote_type (T,S)
751
+ return P (z) ^ Complex {P} (p)
752
+ end
758
753
759
754
function sin (z:: Complex{T} ) where T
760
755
F = float (T)
0 commit comments