[Haskell-cafe] How to calculate de number of digits of an
integer? (was: Is logBase right?)
Bertram Felgenhauer
bertram.felgenhauer at googlemail.com
Sat Aug 29 11:28:57 EDT 2009
Uwe Hollerbach wrote:
> Here's my version... maybe not as elegant as some, but it seems to
> work. For base 2 (or 2^k), it's probably possible to make this even
> more efficient by just walking along the integer as stored in memory,
> but that difference probably won't show up until at least tens of
> thousands of digits.
>
> Uwe
>
> ilogb :: Integer -> Integer -> Integer
> ilogb b n | n < 0 = ilogb b (- n)
> | n < b = 0
> | otherwise = (up 1) - 1
> where up a = if n < (b ^ a)
> then bin (quot a 2) a
> else up (2*a)
> bin lo hi = if (hi - lo) <= 1
> then hi
> else let av = quot (lo + hi) 2
> in if n < (b ^ av)
> then bin lo av
> else bin av hi
We can streamline this algorithm, avoiding the repeated iterated squaring
of the base that (^) does:
-- numDigits b n | n < 0 = 1 + numDigits b (-n)
numDigits b n = 1 + fst (ilog b n) where
ilog b n
| n < b = (0, n)
| otherwise = let (e, r) = ilog (b*b) n
in if r < b then (2*e, r) else (2*e+1, r `div` b)
It's a worthwhile optimization, as timings on n = 2^1000000 show:
Prelude T> length (show n)
301030
(0.48 secs, 17531388 bytes)
Prelude T> numDigits 10 n
301030
(0.10 secs, 4233728 bytes)
Prelude T> ilogb 10 n
301029
(1.00 secs, 43026552 bytes)
(Code compiled with -O2, but the interpreted version is just as fast; the
bulk of the time is spent in gmp anyway.)
Regards,
Bertram
More information about the Haskell-Cafe
mailing list