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 :: Integer -> Integer
integerLog2 Integer
n = Integer -> Integer
forall t p. (Num t, Num p, Bits t) => t -> p
go Integer
n where
go :: t -> p
go t
0 = -p
1
go t
k = p
1 p -> p -> p
forall a. Num a => a -> a -> a
+ t -> p
go (t -> Int -> t
forall a. Bits a => a -> Int -> a
shiftR t
k Int
1)
ceilingLog2 :: Integer -> Integer
ceilingLog2 :: Integer -> Integer
ceilingLog2 Integer
0 = Integer
0
ceilingLog2 Integer
n = Integer
1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer -> Integer
forall t p. (Num t, Num p, Bits t) => t -> p
go (Integer
nInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-Integer
1) where
go :: t -> p
go t
0 = -p
1
go t
k = p
1 p -> p -> p
forall a. Num a => a -> a -> a
+ t -> p
go (t -> Int -> t
forall a. Bits a => a -> Int -> a
shiftR t
k Int
1)
isSquare :: Integer -> Bool
isSquare :: Integer -> Bool
isSquare Integer
n =
if (Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
mod Integer
n Integer
32) Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
rs
then (Integer, Integer) -> Integer
forall a b. (a, b) -> b
snd (Integer -> (Integer, Integer)
integerSquareRoot' Integer
n) Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0
else Bool
False
where
rs :: [Int]
rs = [Int
0,Int
1,Int
4,Int
9,Int
16,Int
17,Int
25] :: [Int]
integerSquareRoot :: Integer -> Integer
integerSquareRoot :: Integer -> Integer
integerSquareRoot = (Integer, Integer) -> Integer
forall a b. (a, b) -> a
fst ((Integer, Integer) -> Integer)
-> (Integer -> (Integer, Integer)) -> Integer -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> (Integer, Integer)
integerSquareRoot'
ceilingSquareRoot :: Integer -> Integer
ceilingSquareRoot :: Integer -> Integer
ceilingSquareRoot Integer
n = (if Integer
rInteger -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>Integer
0 then Integer
uInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
+Integer
1 else Integer
u) where (Integer
u,Integer
r) = Integer -> (Integer, Integer)
integerSquareRoot' Integer
n
integerSquareRoot' :: Integer -> (Integer,Integer)
integerSquareRoot' :: Integer -> (Integer, Integer)
integerSquareRoot' Integer
n
| Integer
nInteger -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<Integer
0 = [Char] -> (Integer, Integer)
forall a. HasCallStack => [Char] -> a
error [Char]
"integerSquareRoot: negative input"
| Integer
nInteger -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<Integer
2 = (Integer
n,Integer
0)
| Bool
otherwise = Integer -> (Integer, Integer)
go Integer
firstGuess
where
k :: Integer
k = Integer -> Integer
integerLog2 Integer
n
firstGuess :: Integer
firstGuess = Integer
2Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^(Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
div (Integer
kInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
+Integer
2) Integer
2)
go :: Integer -> (Integer, Integer)
go Integer
a =
if Integer
m Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
a
then Integer -> (Integer, Integer)
go Integer
a'
else (Integer
a, Integer
r Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
aInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
*(Integer
mInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-Integer
a))
where
(Integer
m,Integer
r) = Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
divMod Integer
n Integer
a
a' :: Integer
a' = Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
div (Integer
m Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
a) Integer
2
integerSquareRootNewton' :: Integer -> (Integer,Integer)
integerSquareRootNewton' :: Integer -> (Integer, Integer)
integerSquareRootNewton' Integer
n
| Integer
nInteger -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<Integer
0 = [Char] -> (Integer, Integer)
forall a. HasCallStack => [Char] -> a
error [Char]
"integerSquareRootNewton: negative input"
| Integer
nInteger -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<Integer
2 = (Integer
n,Integer
0)
| Bool
otherwise = Integer -> (Integer, Integer)
go (Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
div Integer
n Integer
2)
where
go :: Integer -> (Integer, Integer)
go Integer
a =
if Integer
m Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
a
then Integer -> (Integer, Integer)
go Integer
a'
else (Integer
a, Integer
r Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
aInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
*(Integer
mInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-Integer
a))
where
(Integer
m,Integer
r) = Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
divMod Integer
n Integer
a
a' :: Integer
a' = Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
div (Integer
m Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
a) Integer
2