{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}
module Math.NumberTheory.Logarithms ( integerLog10' ) where
#if defined(INTEGER_SIMPLE) && __GLASGOW_HASKELL__ < 702
import GHC.Integer.Logarithms (integerLogBase#)
import GHC.Base (Int(I#))
integerLog10' :: Integer -> Int
integerLog10' m = I# (integerLogBase# 10 m)
#else
import GHC.Base ( Int(I#), Word#, Int#
, int2Word#, eqWord#, neWord#, (-#), and#, uncheckedShiftRL#
#if __GLASGOW_HASKELL__ >= 707
, isTrue#
#endif
)
import GHC.Integer.Logarithms.Compat (integerLog2#, wordLog2#)
integerLog10' :: Integer -> Int
integerLog10' n
| n < 10 = 0
| n < 100 = 1
| otherwise = ex + integerLog10' (n `quot` integerPower 10 ex)
where
ln = I# (integerLog2# n)
u = 1936274
v = 6432163
ex = fromInteger ((u * fromIntegral ln) `quot` v)
integerPower :: Integer -> Int -> Integer
integerPower b (I# e#) = power b (int2Word# e#)
power :: Integer -> Word# -> Integer
power b w#
| isTrue# (w# `eqWord#` 0##) = 1
| isTrue# (w# `eqWord#` 1##) = b
| otherwise = go (wordLog2# w# -# 1#) b (b*b)
where
go 0# l h = if isTrue# ((w# `and#` 1##) `eqWord#` 0##) then l*l else (l*h)
go i# l h
| w# `hasBit#` i# = go (i# -# 1#) (l*h) (h*h)
| otherwise = go (i# -# 1#) (l*l) (l*h)
hasBit# :: Word# -> Int# -> Bool
hasBit# w# i# = isTrue# (((w# `uncheckedShiftRL#` i#) `and#` 1##) `neWord#` 0##)
#if __GLASGOW_HASKELL__ < 707
isTrue# :: Bool -> Bool
isTrue# = id
#endif
#endif