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

Raise informative error for float/integer exponentiation that yields … #12822

Merged
merged 1 commit into from
Aug 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions base/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,14 @@ function showerror(io::IO, ex::DomainError, bt; backtrace=true)
code = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Cint), b-1, true)
if length(code) == 5 && !code[4] # code[4] == fromC
if code[1] in (:log, :log2, :log10, :sqrt) # TODO add :besselj, :besseli, :bessely, :besselk
println(io,"\n$(code[1]) will only return a complex result if called with a complex argument.")
print(io, "try $(code[1]) (complex(x))")
elseif (code[1] == :^ && code[2] == symbol("intfuncs.jl")) || code[1] == :power_by_squaring
println(io, "\nCannot raise an integer x to a negative power -n. Make x a float by adding")
print(io, "a zero decimal (e.g. 2.0^-n instead of 2^-n), or write 1/x^n, float(x)^-n, or (x//1)^-n")
println(io,"\n$(code[1]) will only return a complex result if called with a complex argument. ",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this probably should have been print, not println; you added an extra newline to the output.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stevengj , actually that was the original design. I didn't introduce it. In fact, I'm not getting extraneous newlines comparing the output before and after your commit removing those println (e3d2cb7). Since I didn't notice that behavior, I didn't bother to change the old code.

Before

 _/ |\__'_|_|_|\__'_|  |  Commit 732860a (0 days old master)
|__/                   |  x86_64-apple-darwin14.5.0

julia> log(-2)
ERROR: DomainError:
log will only return a complex result if called with a complex argument.
try log (complex(x))
 in log at math.jl:139

julia> (-2.0)^(2.2)
ERROR: DomainError:
 in ^ at math.jl:275

After

 _/ |\__'_|_|_|\__'_|  |  Commit e3d2cb7 (0 days old master)
|__/                   |  x86_64-apple-darwin14.5.0

julia> log(-2)
ERROR: DomainError:
log will only return a complex result if called with a complex argument. Try log (complex(x)).
 in log at math.jl:139

julia> (-2.0)^(2.2)
ERROR: DomainError:
Exponentiation yielding a complex result requires a complex argument.
Replace x^y with (x+0im)^y, Complex(x)^y, or similar.
 in ^ at math.jl:275

"Try $(code[1]) (complex(x)).")
elseif (code[1] == :^ && code[2] == symbol("intfuncs.jl")) || code[1] == :power_by_squaring #3024
println(io, "\nCannot raise an integer x to a negative power -n. \nMake x a float by adding ",
"a zero decimal (e.g. 2.0^-n instead of 2^-n), or write 1/x^n, float(x)^-n, or (x//1)^-n.")
elseif code[1] == :^ && (code[2] == symbol("promotion.jl") || code[2] == symbol("math.jl"))
println(io, "\nExponentiation yielding a complex result requires a complex argument. ",
"\nReplace x^y with (x+0im)^y, Complex(x)^y, or similar.")
end
break
end
Expand Down Expand Up @@ -173,9 +176,9 @@ function showerror(io::IO, ex::MethodError)
push!(vec_args, isrow ? vec(arg) : arg)
end
if hasrows && applicable(f, vec_args...)
print(io, "\n\nYou might have used a 2d row vector where a 1d column vector was required.")
print(io, "\nNote the difference between 1d column vector [1,2,3] and 2d row vector [1 2 3].")
print(io, "\nYou can convert to a column vector with the vec() function.")
print(io, "\n\nYou might have used a 2d row vector where a 1d column vector was required.",
"\nNote the difference between 1d column vector [1,2,3] and 2d row vector [1 2 3].",
"\nYou can convert to a column vector with the vec() function.")
end
end
# Give a helpful error message if the user likely called a type constructor
Expand All @@ -185,8 +188,8 @@ function showerror(io::IO, ex::MethodError)
arg_types_param[1].name === Type.name)
construct_type = arg_types_param[1].parameters[1]
println(io)
print(io, "This may have arisen from a call to the constructor $construct_type(...),")
print(io, "\nsince type constructors fall back to convert methods.")
print(io, "This may have arisen from a call to the constructor $construct_type(...),",
"\nsince type constructors fall back to convert methods.")
end
show_method_candidates(io, ex)
end
Expand Down
5 changes: 5 additions & 0 deletions test/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -542,3 +542,8 @@ for f in binary_math_functions
@test f(x,[y]) == v
@test f([x],[y]) == v
end

# #3024, #12822
@test_throws DomainError 2 ^ -2
@test_throws DomainError (-2)^(2.2)
@test_throws DomainError (-2.0)^(2.2)