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

WIP: Better DomainError's #9693

Closed
wants to merge 18 commits into from
Closed
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
3 changes: 2 additions & 1 deletion base/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ const Bottom = Union()
# constructors for Core types in boot.jl
call(T::Type{BoundsError}) = Core.call(T)
call(T::Type{BoundsError}, args...) = Core.call(T, args...)
call(T::Type{DivideError}) = Core.call(T)
call(T::Type{DomainError}) = Core.call(T)
call(T::Type{DomainError}, msg) = Core.call(T, msg)
call(T::Type{DivideError}) = Core.call(T)
call(T::Type{OverflowError}) = Core.call(T)
call(T::Type{InexactError}) = Core.call(T)
call(T::Type{MemoryError}) = Core.call(T)
Expand Down
6 changes: 5 additions & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,12 @@ immutable BoundsError <: Exception
BoundsError(a::ANY) = new(a)
BoundsError(a::ANY, i::ANY) = new(a,i)
end
immutable DomainError <: Exception
msg::Any
DomainError() = new()
DomainError(msg::ANY) = new(msg)
end
immutable DivideError <: Exception end
immutable DomainError <: Exception end
immutable OverflowError <: Exception end
immutable InexactError <: Exception end
immutable MemoryError <: Exception end
Expand Down
20 changes: 16 additions & 4 deletions base/combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const _fact_table128 =
0x0688589cc0e9505e2f2fee5580000000, 0xde1bc4d19efcac82445da75b00000000]

function factorial_lookup(n::Integer, table, lim)
n < 0 && throw(DomainError())
n < 0 && throw(DomainError("factorial(n) for n < 0 is undefined"))
n > lim && throw(OverflowError())
n == 0 && return one(n)
@inbounds f = table[n]
Expand All @@ -50,7 +50,7 @@ function gamma(n::Union(Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64))
end

function factorial(n::Integer)
n < 0 && throw(DomainError())
n < 0 && throw(DomainError("factorial(n) for n < 0 is undefined"))
local f::typeof(n*n), i::typeof(n*n)
f = 1
for i = 2:n
Expand Down Expand Up @@ -387,7 +387,12 @@ end

length(f::FixedPartitions) = npartitions(f.n,f.m)

partitions(n::Integer, m::Integer) = n >= 1 && m >= 1 ? FixedPartitions(n,m) : throw(DomainError())
function partitions(n::Integer, m::Integer)
if n <= 0 || m <= 0
throw(DomainError("partitions(n, m) is undefined for n ≤ 0 or m ≤ 0"))
end
return FixedPartitions(n,m)
end

start(f::FixedPartitions) = Int[]
function done(f::FixedPartitions, s::Vector{Int})
Expand Down Expand Up @@ -516,7 +521,14 @@ end

length(p::FixedSetPartitions) = nfixedsetpartitions(length(p.s),p.m)

partitions(s::AbstractVector,m::Int) = length(s) >= 1 && m >= 1 ? FixedSetPartitions(s,m) : throw(DomainError())
function partitions(s::AbstractVector,m::Int)
if isempty(s)
throw(DomainError("partions(s::AbstractVector,m) is undefined for empty vectors"))
else m <= 0
throw(DomainError("partions(s::AbstractVector,m) is undefined for m ≤ 0"))
end
return FixedSetPartitions(s,m)
end

function start(p::FixedSetPartitions)
n = length(p.s)
Expand Down
20 changes: 10 additions & 10 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -310,15 +310,15 @@ for (fJ, fC) in ((:-, :neg), (:~, :com))
end

function <<(x::BigInt, c::Int32)
c < 0 && throw(DomainError())
c < 0 && return BigInt(0)
c == 0 && return x
z = BigInt()
ccall((:__gmpz_mul_2exp, :libgmp), Void, (Ptr{BigInt}, Ptr{BigInt}, Culong), &z, &x, c)
return z
end

function >>(x::BigInt, c::Int32)
c < 0 && throw(DomainError())
c < 0 && return BigInt(0)
c == 0 && return x
z = BigInt()
ccall((:__gmpz_fdiv_q_2exp, :libgmp), Void, (Ptr{BigInt}, Ptr{BigInt}, Culong), &z, &x, c)
Expand Down Expand Up @@ -352,7 +352,7 @@ cmp(x::BigInt, y::Integer) = cmp(x,big(y))
cmp(x::Integer, y::BigInt) = -cmp(y,x)

function cmp(x::BigInt, y::CdoubleMax)
isnan(y) && throw(DomainError())
isnan(y) && throw(DomainError("cmp(BigInt, NAN) is undefined"))
ccall((:__gmpz_cmp_d, :libgmp), Int32, (Ptr{BigInt}, Cdouble), &x, y)
end
cmp(x::CdoubleMax, y::BigInt) = -cmp(y,x)
Expand All @@ -370,10 +370,10 @@ function ^(x::BigInt, y::UInt)
end

function bigint_pow(x::BigInt, y::Integer)
if y<0; throw(DomainError()); end
if x== 1; return x; end
if x==-1; return isodd(y) ? x : -x; end
if y>typemax(UInt); throw(DomainError()); end
y < 0 && throw(DomainError("Cannot raise a BigInt to a negative power $y"))
x == 1 && return x
x == -1 && return isodd(y) ? x : -x
y > typemax(UInt) && throw(ArgumentError("Power must be ≤ $(typemax(UInt)), got $y"))
return x^uint(y)
end

Expand All @@ -383,7 +383,7 @@ end
^(x::Integer, y::BigInt ) = bigint_pow(BigInt(x), y)

function powermod(x::BigInt, p::BigInt, m::BigInt)
p < 0 && throw(DomainError())
p < 0 && throw(DomainError("Cannot raise a BigInt to a negative power $p"))
r = BigInt()
ccall((:__gmpz_powm, :libgmp), Void,
(Ptr{BigInt}, Ptr{BigInt}, Ptr{BigInt}, Ptr{BigInt}),
Expand Down Expand Up @@ -465,14 +465,14 @@ dec(n::BigInt) = base(10, n)
hex(n::BigInt) = base(16, n)

function base(b::Integer, n::BigInt)
2 <= b <= 62 || error("invalid base: $b")
2 <= b <= 62 || throw(ArgumentError("Base must be 2 ≤ n ≤ 62, got $n"))
p = ccall((:__gmpz_get_str,:libgmp), Ptr{UInt8}, (Ptr{UInt8}, Cint, Ptr{BigInt}), C_NULL, b, &n)
len = int(ccall(:strlen, Csize_t, (Ptr{UInt8},), p))
ASCIIString(pointer_to_array(p,len,true))
end

function ndigits0z(x::BigInt, b::Integer=10)
b < 2 && throw(DomainError())
b < 2 && throw(ArgumentError("Base must be ≥ 2, got $b"))
if ispow2(b)
int(ccall((:__gmpz_sizeinbase,:libgmp), Culong, (Ptr{BigInt}, Int32), &x, b))
else
Expand Down
2 changes: 1 addition & 1 deletion base/linalg/cholesky.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ end
chol{T}(A::AbstractMatrix{T}, uplo::Symbol=:U) = (S = promote_type(typeof(chol(one(T))),Float32); S != T ? chol!(convert(AbstractMatrix{S}, A), uplo) : chol!(copy(A), uplo))
function chol!(x::Number, uplo::Symbol=:U)
rx = real(x)
rx == abs(x) || throw(DomainError())
rx == abs(x) || throw(DomainError("chol!(::Number) argument must be a non-negative real number"))
rxr = sqrt(rx)
convert(promote_type(typeof(x), typeof(rxr)), rxr)
end
Expand Down
4 changes: 2 additions & 2 deletions base/linalg/factorization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -511,11 +511,11 @@ eigvals{T<:Number}(x::T; kwargs...) = (val = convert(promote_type(Float32,typeof
#Computes maximum and minimum eigenvalue
function eigmax(A::Union(Number, StridedMatrix); permute::Bool=true, scale::Bool=true)
v = eigvals(A, permute = permute, scale = scale)
iseltype(v,Complex) ? error("DomainError: complex eigenvalues cannot be ordered") : maximum(v)
iseltype(v,Complex) ? throw(DomainError("complex eigenvalues cannot be ordered")) : maximum(v)
end
function eigmin(A::Union(Number, StridedMatrix); permute::Bool=true, scale::Bool=true)
v = eigvals(A, permute = permute, scale = scale)
iseltype(v,Complex) ? error("DomainError: complex eigenvalues cannot be ordered") : minimum(v)
iseltype(v,Complex) ? throw(DomainError("complex eigenvalues cannot be ordered")) : minimum(v)
end

inv(A::Eigen) = A.vectors/Diagonal(A.values)*A.vectors'
Expand Down
7 changes: 5 additions & 2 deletions base/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,11 @@ function bessely(n::Integer, x::BigFloat)
end

function factorial(x::BigFloat)
if x < 0 || !isinteger(x)
throw(DomainError())
if x < 0
throw(DomainError("factorial(n) is undefined for n < 0"))
end
if !isinteger(x)
throw(DomainError("factorial(n) is undefined for non-integer values"))
end
ui = convert(Culong, x)
z = BigFloat()
Expand Down
2 changes: 1 addition & 1 deletion base/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ function make_seed()
end

function make_seed(n::Integer)
n < 0 && throw(DomainError())
n < 0 && throw(DomainError("seed integer must be ≥ 0"))
seed = UInt32[]
while true
push!(seed, n & 0xffffffff)
Expand Down
29 changes: 16 additions & 13 deletions base/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,20 +94,23 @@ function showerror(io::IO, e::LoadError, bt)
end

function showerror(io::IO, e::DomainError, bt)
print(io, "DomainError")
for b in bt
code = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Cint), b, true)
if length(code) == 5 && !code[4] # code[4] == fromC
if code[1] in (:log, :log2, :log10, :sqrt) # TODO add :besselj, :besseli, :bessely, :besselk
print(io, "\n", code[1],
" will only return a complex result if called with a complex argument.",
"\ntry ", code[1], "(complex(x))")
elseif (code[1] == :^ && code[2] == symbol("intfuncs.jl")) ||
code[1] == :power_by_squaring
print(io, "\nCannot raise an integer x to a negative power -n. Make x a float by adding")
print(io, "\na 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, "DomainError")
if isdefined(e, :msg)
print(io, e.msg)
else
for b in bt
code = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Cint), b, true)
if length(code) == 5 && !code[4] # code[4] == fromC
if code[1] in (:log, :log2, :log10, :sqrt) # TODO add :besselj, :besseli, :bessely, :besselk
print(io, code[1],
" will only return a complex result if called with a complex argument.",
"\ntry ", code[1], "(complex(x))")
elseif (code[1] == :^ && code[2] == symbol("intfuncs.jl")) || code[1] == :power_by_squaring
print(io, "Cannot raise an integer x to a negative power -n. Make x a float by adding")
print(io, "\na zero decimal (e.g. 2.0^-n instead of 2^-n), or write 1/x^n, float(x)^-n, or (x//1)^-n")
end
break
end
break
end
end
show_backtrace(io, bt)
Expand Down
18 changes: 18 additions & 0 deletions test/bigint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ b = BigInt("123456789012345678901234567891")
@test b >= a
@test !(b < a)
@test !(b <= a)
@test_throws DomainError cmp(b, NaN)

c = BigInt("246913578024691357802469135780")
@test typeof(a * 2) == BigInt
Expand Down Expand Up @@ -150,11 +151,28 @@ end

@test a+BigInt(1) == b

@test BigInt(5) << -1 == 0
@test BigInt(5) >> -1 == 0
@test BigInt(5) << 0 == 5
@test BigInt(5) >> 0 == 5
@test BigInt(5) << 3 == 40
@test BigInt(5) >> 1 == 2
@test BigInt(-5) << 3 == -40
@test BigInt(-5) >> 1 == -3

@test BigInt(5) ^ 1 == 5
@test_throws DomainError BigInt(5) ^ -1
@test_throws ArgumentError BigInt(5) ^ (UInt128(typemax(UInt)) + 1)

@test base(2, BigInt(1024)) == "10000000000"
@test_throws ArgumentError base(1, BigInt(5))
@test_throws ArgumentError base(63, BigInt(5))

@test ndigits(BigInt(10)) == 2
@test ndigits(BigInt(10), 2) == 4
@test_throws ArgumentError ndigits(BigInt(10), 1)
@test_throws DomainError powermod(BigInt(100), -1, 10)

@test ~BigInt(123) == -124
@test BigInt(123) & BigInt(234) == 106
@test BigInt(123) | BigInt(234) == 251
Expand Down