Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix hang/incorrect result for ndigits(n,b) when b < 0 #8266

Merged
merged 10 commits into from
Sep 20, 2014
1 change: 1 addition & 0 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ function base(b::Integer, n::BigInt)
end

function ndigits0z(x::BigInt, b::Integer=10)
b < 0 && throw(DomainError()) # TODO: make this work correctly.
# mpz_sizeinbase might return an answer 1 too big
n = int(ccall((:__gmpz_sizeinbase,:libgmp), Culong, (Ptr{BigInt}, Int32), &x, b))
abs(x) < big(b)^(n-1) ? n-1 : n
Expand Down
39 changes: 27 additions & 12 deletions base/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -158,29 +158,44 @@ ndigits0z(x::Integer) = ndigits0z(unsigned(abs(x)))

const ndigits_max_mul = WORD_SIZE==32 ? 69000000 : 290000000000000000

function ndigits0z(n::Unsigned, b::Int)
b == 2 && return (sizeof(n)<<3-leading_zeros(n))
b == 8 && return div((sizeof(n)<<3)-leading_zeros(n)+2,3)
b == 16 && return (sizeof(n)<<1)-(leading_zeros(n)>>2)
b == 10 && return ndigits0z(n)
function ndigits0znb(n::Int, b::Int)
d = 0
while ndigits_max_mul < n
n = div(n,b)
while n != 0
n = cld(n,b)
d += 1
end
m = 1
while m <= n
m *= b
d += 1
return d
end

function ndigits0z(n::Unsigned, b::Int)
d = 0
if b < 0
d = ndigits0znb(signed(n), b)
else
b == 2 && return (sizeof(n)<<3-leading_zeros(n))
b == 8 && return div((sizeof(n)<<3)-leading_zeros(n)+2,3)
b == 16 && return (sizeof(n)<<1)-(leading_zeros(n)>>2)
b == 10 && return ndigits0z(n)
while ndigits_max_mul < n
n = div(n,b)
d += 1
end
m = 1
while m <= n
m *= b
d += 1
end
end
return d
end
ndigits0z(x::Integer, b::Integer) = ndigits0z(unsigned(abs(x)),int(b))

ndigitsnb(x::Integer, b::Integer) = x==0 ? 1 : ndigits0znb(x, b)

ndigits(x::Unsigned, b::Integer) = x==0 ? 1 : ndigits0z(x,int(b))
ndigits(x::Unsigned) = x==0 ? 1 : ndigits0z(x)

ndigits(x::Integer, b::Integer) = ndigits(unsigned(abs(x)),int(b))
ndigits(x::Integer, b::Integer) = b >= 0 ? ndigits(unsigned(abs(x)),int(b)) : ndigitsnb(x, b)
ndigits(x::Integer) = ndigits(unsigned(abs(x)))

## integer to string functions ##
Expand Down
2 changes: 1 addition & 1 deletion test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ JULIAHOME = $(abspath ..)
include ../Make.inc

TESTS = all core keywordargs numbers strings unicode collections hashing \
remote iobuffer arrayops reduce reducedim \
remote iobuffer arrayops reduce reducedim intfuncs \
simdloop linalg blas fft dsp sparse bitarray random \
math functional bigint sorting statistics spawn parallel arpack file \
git pkg resolve suitesparse complex version pollfd mpfr broadcast \
Expand Down
16 changes: 16 additions & 0 deletions test/intfuncs.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# issue #8266

@test ndigits(-15, 10) == 2
@test ndigits(-15, -10) == 2
@test ndigits(-1, 10) == 1
@test ndigits(-1, -10) == 2
@test ndigits(2, 10) == 1
@test ndigits(2, -10) == 1
@test ndigits(10, 10) == 2
@test ndigits(10, -10) == 3
@test ndigits(17, 10) == 2
@test ndigits(17, -10) == 3
@test ndigits(unsigned(17), -10) == 3

@test ndigits(146, -3) == 5