Skip to content
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

Powers of Complex{T} are broken for non-AbstractFloat types T #28766

Closed
dpsanders opened this issue Aug 19, 2018 · 3 comments
Closed

Powers of Complex{T} are broken for non-AbstractFloat types T #28766

dpsanders opened this issue Aug 19, 2018 · 3 comments
Labels
complex Complex numbers regression Regression in behavior compared to a previous version

Comments

@dpsanders
Copy link
Contributor

dpsanders commented Aug 19, 2018

z^2 is broken when z::Complex{T} with non-AbstractFloat types T.

This is similar to #22095 which was fixed by #25292.

Using the FloatWrapper type from that PR:

struct FloatWrapper <: Real
    x::Float64
end
 import Base: +, -, *, /, ^, sin, cos, exp, sinh, cosh, convert, isfinite, float, promote_rule
 for op in (:+, :-, :*, :/, :^)
    @eval $op(x::FloatWrapper, y::FloatWrapper) = FloatWrapper($op(x.x, y.x))
end
 for op in (:sin, :cos, :exp, :sinh, :cosh, :-)
    @eval $op(x::FloatWrapper) = FloatWrapper($op(x.x))
end
 for op in (:isfinite,)
    @eval $op(x::FloatWrapper) = $op(x.x)
end
 convert(::Type{FloatWrapper}, x::Int) = FloatWrapper(float(x))
promote_rule(::Type{FloatWrapper}, ::Type{Int}) = FloatWrapper
 float(x::FloatWrapper) = x

we get the following on Julia 0.7, 1.0 and master:

julia> x = FloatWrapper(3.1); y = FloatWrapper(4.1)
FloatWrapper(4.1)

julia> z = Complex(x, y);

julia> z^2
ERROR: StackOverflowError:
Stacktrace:
 [1] Type at ./complex.jl:12 [inlined] (repeats 2 times)
 [2] float at ./complex.jl:967 [inlined]
 [3] _cpow(::Complex{FloatWrapper}, ::Complex{FloatWrapper}) at ./complex.jl:735 (repeats 80000 times)

(Note that display of the type of z is also broken without defining < for the type, which seems strange.)

@JeffBezanson JeffBezanson added the complex Complex numbers label Aug 21, 2018
@dpsanders
Copy link
Contributor Author

Note that this is a regression compared to 0.6.

@JeffBezanson JeffBezanson added the regression Regression in behavior compared to a previous version label Sep 5, 2018
@vtjnash
Copy link
Sponsor Member

vtjnash commented Oct 23, 2020

Seems to be pretty straightforward now, with each attempt printing out the next missing method:

julia> z^2                                                                                                                                                              
ERROR: MethodError: no method matching isinteger(::FloatWrapper)                                                                                                        
Closest candidates are:                                                                                                                                                 
  isinteger(::Integer) at number.jl:20                                                                                                                                  
  isinteger(::Complex) at complex.jl:134                                            
  isinteger(::Rational) at rational.jl:264                                                                                                                              
  ...                                                                               
Stacktrace:                                                                                                                                                             
 [1] _cpow(z::Complex{FloatWrapper}, p::Complex{FloatWrapper})                      
   @ Base ./complex.jl:708                                                          
 [2] ^(z::Complex{FloatWrapper}, p::Complex{FloatWrapper})                          
   @ Base ./complex.jl:784                                                          
 [3] ^(x::Complex{FloatWrapper}, y::Complex{Int64})                                 
   @ Base ./promotion.jl:353                                                        
 [4] ^(z::Complex{FloatWrapper}, n::Int64)                                                                                                                              
   @ Base ./complex.jl:789                                                          
 [5] macro expansion                                                                
   @ ./none:0 [inlined]                                                                                                                                                 
 [6] literal_pow(f::typeof(^), x::Complex{FloatWrapper}, #unused#::Val{2})                                                                                              
   @ Base ./none:0                                                                                                                                                      
 [7] top-level scope                                                                                                                                                    
   @ REPL[11]:1                                                                     

julia> Base.isinteger(x::FloatWrapper) = Base.isinteger(x.x)                        

julia> z^2                                                                                                                                                      [56/222]
ERROR: < not defined for FloatWrapper     
Stacktrace:                                                                         
  [1] error(::String, ::String, ::Type)                                             
    @ Base ./error.jl:42                                                            
  [2] no_op_err(name::String, T::Type)                                              
    @ Base ./promotion.jl:393                                                       
  [3] <(x::FloatWrapper, y::FloatWrapper)                                                                                                                               
    @ Base ./promotion.jl:409                                                       
  [4] <(x::FloatWrapper, y::Int64)                                                                                                                                      
    @ Base ./promotion.jl:359                                                                                                                                           
  [5] signbit(x::FloatWrapper)                                                      
    @ Base ./number.jl:128                                                          
  [6] abs(x::FloatWrapper)                                                                                                                                              
    @ Base ./number.jl:138                                                          
  [7] _cpow(z::Complex{FloatWrapper}, p::Complex{FloatWrapper})
    @ Base ./complex.jl:708
  [8] ^(z::Complex{FloatWrapper}, p::Complex{FloatWrapper})
    @ Base ./complex.jl:784
  [9] ^(x::Complex{FloatWrapper}, y::Complex{Int64})
    @ Base ./promotion.jl:353
 [10] ^(z::Complex{FloatWrapper}, n::Int64)
    @ Base ./complex.jl:789
 [11] macro expansion
    @ ./none:0 [inlined]
 [12] literal_pow(f::typeof(^), x::Complex{FloatWrapper}, #unused#::Val{2})
    @ Base ./none:0
 [13] top-level scope
    @ REPL[14]:1

julia> Base.:(<)(x::FloatWrapper, y::FloatWrapper) = <(x.x, y.x)

julia> z^2
ERROR: promotion of types FloatWrapper and Int32 failed to change any arguments
Stacktrace:
  [1] error(::String, ::String, ::String)
    @ Base ./error.jl:42
  [2] sametype_error(input::Tuple{FloatWrapper, Int32})
    @ Base ./promotion.jl:316
  [3] not_sametype(x::Tuple{FloatWrapper, Int32}, y::Tuple{FloatWrapper, Int32})
    @ Base ./promotion.jl:310
  [4] promote
    @ ./promotion.jl:293 [inlined]
  [5] <(x::FloatWrapper, y::Int32)
    @ Base ./promotion.jl:359
  [6] _cpow(z::Complex{FloatWrapper}, p::Complex{FloatWrapper})
    @ Base ./complex.jl:708
  [7] ^
    @ ./complex.jl:784 [inlined]
  [8] ^
    @ ./promotion.jl:353 [inlined]
  [9] ^
    @ ./complex.jl:789 [inlined]
 [10] macro expansion
    @ ./none:0 [inlined]
 [11] literal_pow(f::typeof(^), x::Complex{FloatWrapper}, #unused#::Val{2})
    @ Base ./none:0
 [12] top-level scope
    @ REPL[16]:1

julia> Base.promote_rule(::Type{FloatWrapper}, ::Type{Int32}) = FloatWrapper

julia> z^2
ERROR: MethodError: no method matching Int64(::FloatWrapper)
Closest candidates are:
  (::Type{T})(::T) where T<:Number at boot.jl:760
  (::Type{T})(::AbstractChar) where T<:Union{AbstractChar, Number} at char.jl:50
  (::Type{T})(::BigInt) where T<:Union{Int128, Int16, Int32, Int64, Int8} at gmp.jl:356
  ...
Stacktrace:
 [1] convert(#unused#::Type{Int64}, x::FloatWrapper)
   @ Base ./number.jl:7
 [2] _cpow(z::Complex{FloatWrapper}, p::Complex{FloatWrapper})
   @ Base ./complex.jl:716
 [3] ^
   @ ./complex.jl:784 [inlined]
 [4] ^
   @ ./promotion.jl:353 [inlined]
 [5] ^
   @ ./complex.jl:789 [inlined]
 [6] macro expansion
   @ ./none:0 [inlined]
 [7] literal_pow(f::typeof(^), x::Complex{FloatWrapper}, #unused#::Val{2})
   @ Base ./none:0
 [8] top-level scope
   @ REPL[18]:1

julia> Base.Int64(x::FloatWrapper) = Int64(x.x)

julia> z^2
FloatWrapper(-7.1999999999999975) + FloatWrapper(25.419999999999998)*im

And then covering other branches:

julia> Complex(FloatWrapper(23), FloatWrapper(-32.3))^Complex(FloatWrapper(2), FloatWrapper(2))
ERROR: StackOverflowError:
Stacktrace:
 [1] hypot(x::FloatWrapper, y::FloatWrapper)
   @ Base.Math ./math.jl:632
julia> Base.hypot(x::FloatWrapper, y::FloatWrapper) = FloatWrapper(hypot(x.x, y.x))
julia> Complex(FloatWrapper(23), FloatWrapper(-32.3))^Complex(FloatWrapper(2), FloatWrapper(2))
FloatWrapper(7146.957962127675) - FloatWrapper(7766.5853056105225)*im

julia> Complex(FloatWrapper(23), FloatWrapper(0))^Complex(FloatWrapper(2), FloatWrapper(2))
ERROR: StackOverflowError:
Stacktrace:
 [1] log(x::FloatWrapper)
   @ Base.Math ./special/log.jl:395
julia> Base.log(x::FloatWrapper) = FloatWrapper(log(x.x))
julia> Complex(FloatWrapper(23), FloatWrapper(0))^Complex(FloatWrapper(2), FloatWrapper(2))
FloatWrapper(528.9606524712632) - FloatWrapper(6.451987071866881)*im

julia> Complex(FloatWrapper(23.5), FloatWrapper(3.5))^Complex(FloatWrapper(2.5), FloatWrapper(.5))
ERROR: StackOverflowError:
Stacktrace:
 [1] atan(y::FloatWrapper, x::FloatWrapper)
   @ Base.Math ./math.jl:708
julia> Base.atan(x::FloatWrapper, y::FloatWrapper) = FloatWrapper(atan(x.x, y.x))
julia> Complex(FloatWrapper(23.5), FloatWrapper(3.5))^Complex(FloatWrapper(2.5), FloatWrapper(.5))
FloatWrapper(-954.5551074145027) + FloatWrapper(2370.5218188789154)*im

@vtjnash vtjnash closed this as completed Oct 23, 2020
@oscardssmith
Copy link
Member

To me, it seems like we might be able to get better wrt generic special functions. Having fallback methods which use variable numbers of terms and check for convergence seems like a good improvement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
complex Complex numbers regression Regression in behavior compared to a previous version
Projects
None yet
Development

No branches or pull requests

4 participants