Skip to content

Commit

Permalink
faster digits(::BigInt) (JuliaLang#37075)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevengj authored and simeonschaub committed Aug 29, 2020
1 parent 4c6406d commit 4282ce3
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 1 deletion.
20 changes: 19 additions & 1 deletion base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions test/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 4282ce3

Please sign in to comment.