diff --git a/base/gmp.jl b/base/gmp.jl index 7696c56b15e0e..27344bf470dcc 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -578,26 +578,21 @@ oct(n::BigInt, pad::Int) = base( 8, n, pad) dec(n::BigInt, pad::Int) = base(10, n, pad) hex(n::BigInt, pad::Int) = base(16, n, pad) -function base(b::Integer, n::BigInt) +function base(b::Integer, n::BigInt, pad::Integer=1) + b < 0 && return base(Int(b), n, pad, (b>0) & (n.size<0)) 2 <= b <= 62 || throw(ArgumentError("base must be 2 ≤ base ≤ 62, got $b")) - nd = ndigits(n, b) - str = Base._string_n(n < 0 ? nd+1 : nd) - ccall((:__gmpz_get_str,:libgmp), Ptr{UInt8}, (Ptr{UInt8}, Cint, Ptr{BigInt}), str, b, &n) - return str -end - -function base(b::Integer, n::BigInt, pad::Integer) - s = base(b, n) - buf = IOBuffer() - if n < 0 - s = s[2:end] - write(buf, '-') + nd1 = ndigits(n, b) + nd = max(nd1, pad) + str = Base._string_n(nd + isneg(n) + 1) # +1 for final '\0' + ptr = pointer(str) + MPZ.get_str!(ptr + nd - nd1, b, n) + for i = (0:nd-nd1-1) + isneg(n) + unsafe_store!(ptr+i, '0' % UInt8) end - for i in 1:pad-sizeof(s) # `s` is known to be ASCII, and `length` is slower - write(buf, '0') - end - write(buf, s) - String(buf) + isneg(n) && unsafe_store!(ptr, '-' % UInt8) + str.len -= 1 # final '\0' + iszero(n) && pad < 1 && (str.len -= 1) + str end function ndigits0z(x::BigInt, b::Integer=10) diff --git a/test/bigint.jl b/test/bigint.jl index 4bf485ccb8e29..771e6343e770b 100644 --- a/test/bigint.jl +++ b/test/bigint.jl @@ -333,6 +333,12 @@ let padding = 4, low = big(4), high = big(2^20) @test hex(-high, padding) == "-100000" end +# respect 0-padding on big(0) +for f in (bin, oct, dec, hex) + @test f(big(0), 0) == "" +end +@test base(rand(2:62), big(0), 0) == "" + @test isqrt(big(4)) == 2 @test isqrt(big(5)) == 2