From a2f4a056912d05d77e865bda59b317088877a338 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Sat, 15 Jul 2017 19:18:11 +0200 Subject: [PATCH] digits!: check for typemax only when applicable (#16844) --- base/gmp.jl | 4 +++- base/int.jl | 2 ++ base/intfuncs.jl | 11 ++++++++++- base/random.jl | 3 +-- test/bigint.jl | 3 +++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/base/gmp.jl b/base/gmp.jl index 4e61599e6697b..ae7de27d0e236 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -9,7 +9,7 @@ import Base: *, +, -, /, <, <<, >>, >>>, <=, ==, >, >=, ^, (~), (&), (|), xor, ndigits, promote_rule, rem, show, isqrt, string, powermod, sum, trailing_zeros, trailing_ones, count_ones, base, tryparse_internal, bin, oct, dec, hex, isequal, invmod, prevpow2, nextpow2, ndigits0zpb, - widen, signed, unsafe_trunc, trunc, iszero, big, flipsign, signbit + widen, signed, unsafe_trunc, trunc, iszero, big, flipsign, signbit, hastypemax if Clong == Int32 const ClongMax = Union{Int8, Int16, Int32} @@ -228,6 +228,8 @@ signed(x::BigInt) = x convert(::Type{BigInt}, x::BigInt) = x +hastypemax(::Type{BigInt}) = false + function tryparse_internal(::Type{BigInt}, s::AbstractString, startpos::Int, endpos::Int, base_::Integer, raise::Bool) _n = Nullable{BigInt}() diff --git a/base/int.jl b/base/int.jl index 5d9d1036ca52d..719be7c6daa71 100644 --- a/base/int.jl +++ b/base/int.jl @@ -29,6 +29,8 @@ const BitIntegerSmall = Union{BitIntegerSmall_types...} const BitSigned64T = Union{Type{Int8}, Type{Int16}, Type{Int32}, Type{Int64}} const BitUnsigned64T = Union{Type{UInt8}, Type{UInt16}, Type{UInt32}, Type{UInt64}} +const BitIntegerType = Union{map(T->Type{T}, BitInteger_types)...} + throw_inexacterror(f::Symbol, ::Type{T}, val) where T = (@_noinline_meta; throw(InexactError(f, T, val))) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 23db5c5bd8f94..1aafd0dccb905 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -743,6 +743,14 @@ function digits(T::Type{<:Integer}, n::Integer, base::Integer=10, pad::Integer=1 digits!(zeros(T, ndigits(n, base, pad)), n, base) end +""" + hastypemax(T::Type) -> Bool + +Return `true` if and only if `typemax(T)` is defined. +""" +hastypemax(::Base.BitIntegerType) = true +hastypemax(::Type{T}) where {T} = applicable(typemax, T) + """ digits!(array, n::Integer, base::Integer=10) @@ -772,7 +780,8 @@ julia> digits!([2,2,2,2,2,2], 10, 2) function digits!(a::AbstractVector{T}, n::Integer, base::Integer=10) where T<:Integer base < 0 && isa(n, Unsigned) && return digits!(a, convert(Signed, n), base) 2 <= abs(base) || throw(ArgumentError("base must be ≥ 2 or ≤ -2, got $base")) - abs(base) - 1 <= typemax(T) || throw(ArgumentError("type $T too small for base $base")) + hastypemax(T) && abs(base) - 1 > typemax(T) && + throw(ArgumentError("type $T too small for base $base")) for i in eachindex(a) if base > 0 a[i] = rem(n, base) diff --git a/base/random.jl b/base/random.jl index e73be11ff5560..407bdeed8ec17 100644 --- a/base/random.jl +++ b/base/random.jl @@ -28,8 +28,7 @@ mutable struct Close1Open2 <: FloatInterval end ## RandomDevice -const BitIntegerType = Union{map(T->Type{T}, Base.BitInteger_types)...} -const BoolBitIntegerType = Union{Type{Bool},BitIntegerType} +const BoolBitIntegerType = Union{Type{Bool},Base.BitIntegerType} const BoolBitIntegerArray = Union{Array{Bool},Base.BitIntegerArray} if Sys.iswindows() diff --git a/test/bigint.jl b/test/bigint.jl index 1ef6b713e56eb..341d692bf4d2a 100644 --- a/test/bigint.jl +++ b/test/bigint.jl @@ -289,6 +289,9 @@ end @test Base.ndigits0zpb(big(0), big(rand(2:100))) == 0 +# digits with BigInt bases (#16844) +@test digits(big(2)^256, big(2)^128) == [0, 0, 1] + # conversion from float @test BigInt(2.0) == BigInt(2.0f0) == BigInt(big(2.0)) == 2 @test_throws InexactError convert(BigInt, 2.1)