diff --git a/base/gmp.jl b/base/gmp.jl index d2a2ab3385ba4..be2d8128edde5 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -10,7 +10,7 @@ import .Base: *, +, -, /, <, <<, >>, >>>, <=, ==, >, >=, ^, (~), (&), (|), xor, sum, trailing_zeros, trailing_ones, count_ones, tryparse_internal, bin, oct, dec, hex, isequal, invmod, _prevpow2, _nextpow2, ndigits0zpb, widen, signed, unsafe_trunc, trunc, iszero, isone, big, flipsign, signbit, - sign, hastypemax, isodd + sign, hastypemax, isodd, digits! if Clong == Int32 const ClongMax = Union{Int8, Int16, Int32} @@ -694,6 +694,24 @@ function string(n::BigInt; base::Integer = 10, pad::Integer = 1) String(sv) end +function digits!(a::AbstractVector{T}, n::BigInt; base::Integer = 10) where {T<:Integer} + if 2 ≤ base ≤ 62 + s = codeunits(string(n; base)) + i, j = firstindex(a)-1, length(s)+1 + lasti = min(lastindex(a), firstindex(a) + length(s)-1 - isneg(n)) + while i < lasti + # base ≤ 36: 0-9, plus a-z for 10-35 + # base > 36: 0-9, plus A-Z for 10-35 and a-z for 36..61 + x = s[j -= 1] + a[i += 1] = base ≤ 36 ? (x>0x39 ? x-0x57 : x-0x30) : (x>0x39 ? (x>0x60 ? x-0x3d : x-0x37) : x-0x30) + end + lasti = lastindex(a) + while i < lasti; a[i+=1] = zero(T); end + return isneg(n) ? map!(-,a,a) : a + end + return invoke(digits!, Tuple{typeof(a), Integer}, a, n; base) # slow generic fallback +end + function ndigits0zpb(x::BigInt, b::Integer) b < 2 && throw(DomainError(b, "`b` cannot be less than 2.")) x.size == 0 && return 0 # for consistency with other ndigits0z methods diff --git a/test/gmp.jl b/test/gmp.jl index d5e70f66a3796..96ffdedb7a93c 100644 --- a/test/gmp.jl +++ b/test/gmp.jl @@ -293,6 +293,16 @@ let s, n = bigfib(1000001) @test startswith(s, "316047687386689") end +@testset "digits" begin + n = Int64(2080310129088201558) + N = big(n) + for base in (2,7,10,11,16,30,50,62,64,100), pad in (0,1,10,100) + @test digits(n; base, pad) == digits(N; base, pad) + @test digits(-n; base, pad) == digits(-N; base, pad) + @test digits!(Vector{Int}(undef, pad), n; base) == digits!(Vector{Int}(undef, pad), N; base) + end +end + # serialization (#5133) let n = parse(BigInt, "359334085968622831041960188598043661065388726959079837"), b = IOBuffer()