Skip to content

Commit

Permalink
Improve speed of ndigits0z(::BigInt) using logarithms (#8743).
Browse files Browse the repository at this point in the history
(cherry picked from commit 5445e05)

Conflicts:
	base/gmp.jl

From #8752
  • Loading branch information
simonbyrne authored and ivarne committed Oct 27, 2014
1 parent 76a8cc1 commit 3816e88
Showing 1 changed file with 19 additions and 3 deletions.
22 changes: 19 additions & 3 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -448,9 +448,25 @@ function base(b::Integer, n::BigInt)
end

function ndigits0z(x::BigInt, b::Integer=10)
# mpz_sizeinbase might return an answer 1 too big
n = int(ccall((:__gmpz_sizeinbase,:libgmp), Culong, (Ptr{BigInt}, Int32), &x, b))
ispow2(b) || abs(x) >= big(b)^(n-1) ? n : n-1
b < 2 && throw(DomainError())
if ispow2(b)
int(ccall((:__gmpz_sizeinbase,:libgmp), Culong, (Ptr{BigInt}, Int32), &x, b))
else
# non-base 2 mpz_sizeinbase might return an answer 1 too big
# use property that log(b, x) < ndigits(x, b) <= log(b, x) + 1
n = int(ccall((:__gmpz_sizeinbase,:libgmp), Culong, (Ptr{BigInt}, Int32), &x, 2))
lb = log2(b) # assumed accurate to <1ulp (true for openlibm)
q,r = divrem(n,lb)
iq = int(q)
maxerr = q*eps(lb) # maximum error in remainder
if r-1.0 < maxerr
abs(x) >= big(b)^iq ? iq+1 : iq
elseif lb-r < maxerr
abs(x) >= big(b)^(iq+1) ? iq+2 : iq+1
else
iq+1
end
end
end
ndigits(x::BigInt, b::Integer=10) = x.size == 0 ? 1 : ndigits0z(x,b)

Expand Down

0 comments on commit 3816e88

Please sign in to comment.