{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash #-}
#if __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE Trustworthy #-}
#endif
module Math.NumberTheory.Logarithms
(
integerLogBase
, integerLog2
, integerLog10
, naturalLogBase
, naturalLog2
, naturalLog10
, intLog2
, wordLog2
, integerLogBase'
, integerLog2'
, integerLog10'
, intLog2'
, wordLog2'
) where
import GHC.Exts
import Data.Bits
import Data.Array.Unboxed
import Numeric.Natural
#ifdef MIN_VERSION_ghc_bignum
import qualified GHC.Num.Natural as BN
#endif
import GHC.Integer.Logarithms.Compat
#if MIN_VERSION_base(4,8,0) && defined(MIN_VERSION_integer_gmp)
import GHC.Integer.GMP.Internals (Integer (..))
import GHC.Natural
#endif
#if CheckBounds
import Data.Array.IArray (IArray, (!))
#else
import Data.Array.Base (unsafeAt)
#endif
integerLogBase :: Integer -> Integer -> Int
integerLogBase :: Integer -> Integer -> Int
integerLogBase Integer
b Integer
n
| Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
1 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error [Char]
"Math.NumberTheory.Logarithms.integerLogBase: argument must be positive."
| Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
b = Int
0
| Integer
b Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
2 = Integer -> Int
integerLog2' Integer
n
| Integer
b Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
2 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error [Char]
"Math.NumberTheory.Logarithms.integerLogBase: base must be greater than one."
| Bool
otherwise = Integer -> Integer -> Int
integerLogBase' Integer
b Integer
n
integerLog2 :: Integer -> Int
integerLog2 :: Integer -> Int
integerLog2 Integer
n
| Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
1 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error [Char]
"Math.NumberTheory.Logarithms.integerLog2: argument must be positive"
| Bool
otherwise = Int# -> Int
I# (Integer -> Int#
integerLog2# Integer
n)
naturalLogBase :: Natural -> Natural -> Int
naturalLogBase :: Natural -> Natural -> Int
naturalLogBase Natural
b Natural
n
| Natural
n Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural
1 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error [Char]
"Math.NumberTheory.Logarithms.naturalLogBase: argument must be positive."
| Natural
n Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural
b = Int
0
| Natural
b Natural -> Natural -> Bool
forall a. Eq a => a -> a -> Bool
== Natural
2 = Natural -> Int
naturalLog2' Natural
n
| Natural
b Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural
2 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error [Char]
"Math.NumberTheory.Logarithms.naturalLogBase: base must be greater than one."
| Bool
otherwise = Natural -> Natural -> Int
naturalLogBase' Natural
b Natural
n
naturalLog2 :: Natural -> Int
naturalLog2 :: Natural -> Int
naturalLog2 Natural
n
| Natural
n Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural
1 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error [Char]
"Math.NumberTheory.Logarithms.naturalLog2: argument must be non-zero"
| Bool
otherwise = Int# -> Int
I# (Natural -> Int#
naturalLog2# Natural
n)
intLog2 :: Int -> Int
intLog2 :: Int -> Int
intLog2 (I# Int#
i#)
| Int# -> Bool
isTrue# (Int#
i# Int# -> Int# -> Int#
<# Int#
1#) = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error [Char]
"Math.NumberTheory.Logarithms.intLog2: argument must be positive"
| Bool
otherwise = Int# -> Int
I# (Word# -> Int#
wordLog2# (Int# -> Word#
int2Word# Int#
i#))
wordLog2 :: Word -> Int
wordLog2 :: Word -> Int
wordLog2 (W# Word#
w#)
| Int# -> Bool
isTrue# (Word#
w# Word# -> Word# -> Int#
`eqWord#` Word#
0##) = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error [Char]
"Math.NumberTheory.Logarithms.wordLog2: argument must not be 0."
| Bool
otherwise = Int# -> Int
I# (Word# -> Int#
wordLog2# Word#
w#)
integerLog2' :: Integer -> Int
integerLog2' :: Integer -> Int
integerLog2' Integer
n = Int# -> Int
I# (Integer -> Int#
integerLog2# Integer
n)
naturalLog2' :: Natural -> Int
naturalLog2' :: Natural -> Int
naturalLog2' Natural
n = Int# -> Int
I# (Natural -> Int#
naturalLog2# Natural
n)
intLog2' :: Int -> Int
intLog2' :: Int -> Int
intLog2' (I# Int#
i#) = Int# -> Int
I# (Word# -> Int#
wordLog2# (Int# -> Word#
int2Word# Int#
i#))
wordLog2' :: Word -> Int
wordLog2' :: Word -> Int
wordLog2' (W# Word#
w#) = Int# -> Int
I# (Word# -> Int#
wordLog2# Word#
w#)
integerLog10 :: Integer -> Int
integerLog10 :: Integer -> Int
integerLog10 Integer
n
| Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
1 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error [Char]
"Math.NumberTheory.Logarithms.integerLog10: argument must be positive"
| Bool
otherwise = Integer -> Int
integerLog10' Integer
n
naturalLog10 :: Natural -> Int
naturalLog10 :: Natural -> Int
naturalLog10 Natural
n
| Natural
n Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural
1 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error [Char]
"Math.NumberTheory.Logarithms.naturalaLog10: argument must be non-zero"
| Bool
otherwise = Natural -> Int
naturalLog10' Natural
n
integerLog10' :: Integer -> Int
integerLog10' :: Integer -> Int
integerLog10' Integer
n
| Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
10 = Int
0
| Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
100 = Int
1
| Bool
otherwise = Int
ex Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Integer -> Int
integerLog10' (Integer
n Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Integer
10 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
ex)
where
ln :: Int
ln = Int# -> Int
I# (Integer -> Int#
integerLog2# Integer
n)
u :: Integer
u = Integer
1936274
v :: Integer
v = Integer
6432163
ex :: Int
ex = Integer -> Int
forall a. Num a => Integer -> a
fromInteger ((Integer
u Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
ln) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Integer
v)
naturalLog10' :: Natural -> Int
naturalLog10' :: Natural -> Int
naturalLog10' Natural
n
| Natural
n Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural
10 = Int
0
| Natural
n Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural
100 = Int
1
| Bool
otherwise = Int
ex Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Natural -> Int
naturalLog10' (Natural
n Natural -> Natural -> Natural
forall a. Integral a => a -> a -> a
`quot` Natural
10 Natural -> Int -> Natural
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
ex)
where
ln :: Int
ln = Int# -> Int
I# (Natural -> Int#
naturalLog2# Natural
n)
u :: Integer
u = Integer
1936274
v :: Integer
v = Integer
6432163
ex :: Int
ex = Integer -> Int
forall a. Num a => Integer -> a
fromInteger ((Integer
u Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
ln) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Integer
v)
integerLogBase' :: Integer -> Integer -> Int
integerLogBase' :: Integer -> Integer -> Int
integerLogBase' Integer
b Integer
n
| Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
b = Int
0
| Int
lnInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
lb Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
lb = Int
1
| Integer
b Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
33 = let bi :: Int
bi = Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
b
ix :: Int
ix = Int
2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
biInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
4
u :: Int
u = UArray Int Int
logArr UArray Int Int -> Int -> Int
forall i. Ix i => UArray i Int -> Int -> Int
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> Int -> e
`unsafeAt` Int
ix
v :: Int
v = UArray Int Int
logArr UArray Int Int -> Int -> Int
forall i. Ix i => UArray i Int -> Int -> Int
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> Int -> e
`unsafeAt` (Int
ixInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
ex :: Int
ex = Integer -> Int
forall a. Num a => Integer -> a
fromInteger ((Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
u Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
ln) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
v)
in case Int
u of
Int
1 -> Int
ln Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
v
Int
_ -> Int
ex Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Integer -> Integer -> Int
integerLogBase' Integer
b (Integer
n Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Integer
b Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
ex)
| Bool
otherwise = let
bi :: Int
bi = Integer -> Int
forall a. Num a => Integer -> a
fromInteger (Integer
b Integer -> Int -> Integer
forall a. Bits a => a -> Int -> a
`shiftR` (Int
lbInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
4))
ix :: Int
ix = Int
2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
biInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
2
u :: Integer
u = Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Integer) -> Int -> Integer
forall a b. (a -> b) -> a -> b
$ UArray Int Int
logArr UArray Int Int -> Int -> Int
forall i. Ix i => UArray i Int -> Int -> Int
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> Int -> e
`unsafeAt` Int
ix
v :: Integer
v = Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Integer) -> Int -> Integer
forall a b. (a -> b) -> a -> b
$ UArray Int Int
logArr UArray Int Int -> Int -> Int
forall i. Ix i => UArray i Int -> Int -> Int
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> Int -> e
`unsafeAt` (Int
ixInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
w :: Integer
w = Integer
v Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
uInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
*Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
lbInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
4)
ex :: Int
ex = Integer -> Int
forall a. Num a => Integer -> a
fromInteger ((Integer
u Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
ln) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Integer
w)
in Int
ex Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Integer -> Integer -> Int
integerLogBase' Integer
b (Integer
n Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Integer
b Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
ex)
where
lb :: Int
lb = Integer -> Int
integerLog2' Integer
b
ln :: Int
ln = Integer -> Int
integerLog2' Integer
n
naturalLogBase' :: Natural -> Natural -> Int
naturalLogBase' :: Natural -> Natural -> Int
naturalLogBase' Natural
b Natural
n
| Natural
n Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural
b = Int
0
| Int
lnInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
lb Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
lb = Int
1
| Natural
b Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural
33 = let bi :: Int
bi = Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
b
ix :: Int
ix = Int
2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
biInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
4
u :: Int
u = UArray Int Int
logArr UArray Int Int -> Int -> Int
forall i. Ix i => UArray i Int -> Int -> Int
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> Int -> e
`unsafeAt` Int
ix
v :: Int
v = UArray Int Int
logArr UArray Int Int -> Int -> Int
forall i. Ix i => UArray i Int -> Int -> Int
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> Int -> e
`unsafeAt` (Int
ixInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
ex :: Int
ex = Natural -> Int
forall a. Num a => Natural -> a
fromNatural ((Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
u Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
* Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
ln) Natural -> Natural -> Natural
forall a. Integral a => a -> a -> a
`quot` Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
v)
in case Int
u of
Int
1 -> Int
ln Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
v
Int
_ -> Int
ex Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Natural -> Natural -> Int
naturalLogBase' Natural
b (Natural
n Natural -> Natural -> Natural
forall a. Integral a => a -> a -> a
`quot` Natural
b Natural -> Int -> Natural
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
ex)
| Bool
otherwise = let
bi :: Int
bi = Natural -> Int
forall a. Num a => Natural -> a
fromNatural (Natural
b Natural -> Int -> Natural
forall a. Bits a => a -> Int -> a
`shiftR` (Int
lbInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
4))
ix :: Int
ix = Int
2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
biInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
2
u :: Natural
u = Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Natural) -> Int -> Natural
forall a b. (a -> b) -> a -> b
$ UArray Int Int
logArr UArray Int Int -> Int -> Int
forall i. Ix i => UArray i Int -> Int -> Int
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> Int -> e
`unsafeAt` Int
ix
v :: Natural
v = Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Natural) -> Int -> Natural
forall a b. (a -> b) -> a -> b
$ UArray Int Int
logArr UArray Int Int -> Int -> Int
forall i. Ix i => UArray i Int -> Int -> Int
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> Int -> e
`unsafeAt` (Int
ixInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
w :: Natural
w = Natural
v Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
+ Natural
uNatural -> Natural -> Natural
forall a. Num a => a -> a -> a
*Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
lbInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
4)
ex :: Int
ex = Natural -> Int
forall a. Num a => Natural -> a
fromNatural ((Natural
u Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
* Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
ln) Natural -> Natural -> Natural
forall a. Integral a => a -> a -> a
`quot` Natural
w)
in Int
ex Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Natural -> Natural -> Int
naturalLogBase' Natural
b (Natural
n Natural -> Natural -> Natural
forall a. Integral a => a -> a -> a
`quot` Natural
b Natural -> Int -> Natural
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
ex)
where
lb :: Int
lb = Natural -> Int
naturalLog2' Natural
b
ln :: Int
ln = Natural -> Int
naturalLog2' Natural
n
logArr :: UArray Int Int
logArr :: UArray Int Int
logArr = (Int, Int) -> [Int] -> UArray Int Int
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
(i, i) -> [e] -> a i e
listArray (Int
0, Int
61)
[ Int
1 , Int
1,
Int
190537 , Int
301994,
Int
1 , Int
2,
Int
1936274 , Int
4495889,
Int
190537 , Int
492531,
Int
91313 , Int
256348,
Int
1 , Int
3,
Int
190537 , Int
603988,
Int
1936274 , Int
6432163,
Int
1686227 , Int
5833387,
Int
190537 , Int
683068,
Int
5458 , Int
20197,
Int
91313 , Int
347661,
Int
416263 , Int
1626294,
Int
1 , Int
4,
Int
32631 , Int
133378,
Int
190537 , Int
794525,
Int
163451 , Int
694328,
Int
1936274 , Int
8368437,
Int
1454590 , Int
6389021,
Int
1686227 , Int
7519614,
Int
785355 , Int
3552602,
Int
190537 , Int
873605,
Int
968137 , Int
4495889,
Int
5458 , Int
25655,
Int
190537 , Int
905982,
Int
91313 , Int
438974,
Int
390321 , Int
1896172,
Int
416263 , Int
2042557,
Int
709397 , Int
3514492,
Int
1 , Int
5
]
#if CheckBounds
unsafeAt :: (IArray a e, Ix i) => a i e -> i -> e
unsafeAt = (!)
#endif
fromNatural :: Num a => Natural -> a
fromNatural :: forall a. Num a => Natural -> a
fromNatural = Natural -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral
naturalLog2# :: Natural -> Int#
#ifdef MIN_VERSION_ghc_bignum
naturalLog2# :: Natural -> Int#
naturalLog2# Natural
n = Word# -> Int#
word2Int# (Natural -> Word#
BN.naturalLog2# Natural
n)
#else
#if MIN_VERSION_base(4,8,0) && defined(MIN_VERSION_integer_gmp)
naturalLog2# (NatS# b) = wordLog2# b
naturalLog2# (NatJ# n) = integerLog2# (Jp# n)
#else
naturalLog2# n = integerLog2# (toInteger n)
#endif
#endif
#if __GLASGOW_HASKELL__ < 707
isTrue# :: Bool -> Bool
isTrue# = id
#endif