module Math.Combinat.Numbers.Integers
(
integerLog2
, ceilingLog2
, isSquare
, integerSquareRoot
, ceilingSquareRoot
, integerSquareRoot'
, integerSquareRootNewton'
)
where
import Data.List ( group , sort )
import Data.Bits
import System.Random
integerLog2 :: Integer -> Integer
integerLog2 n = go n where
go 0 = -1
go k = 1 + go (shiftR k 1)
ceilingLog2 :: Integer -> Integer
ceilingLog2 0 = 0
ceilingLog2 n = 1 + go (n-1) where
go 0 = -1
go k = 1 + go (shiftR k 1)
isSquare :: Integer -> Bool
isSquare n =
if (fromIntegral $ mod n 32) `elem` rs
then snd (integerSquareRoot' n) == 0
else False
where
rs = [0,1,4,9,16,17,25] :: [Int]
integerSquareRoot :: Integer -> Integer
integerSquareRoot = fst . integerSquareRoot'
ceilingSquareRoot :: Integer -> Integer
ceilingSquareRoot n = (if r>0 then u+1 else u) where (u,r) = integerSquareRoot' n
integerSquareRoot' :: Integer -> (Integer,Integer)
integerSquareRoot' n
| n<0 = error "integerSquareRoot: negative input"
| n<2 = (n,0)
| otherwise = go firstGuess
where
k = integerLog2 n
firstGuess = 2^(div (k+2) 2)
go a =
if m < a
then go a'
else (a, r + a*(m-a))
where
(m,r) = divMod n a
a' = div (m + a) 2
integerSquareRootNewton' :: Integer -> (Integer,Integer)
integerSquareRootNewton' n
| n<0 = error "integerSquareRootNewton: negative input"
| n<2 = (n,0)
| otherwise = go (div n 2)
where
go a =
if m < a
then go a'
else (a, r + a*(m-a))
where
(m,r) = divMod n a
a' = div (m + a) 2