-
Notifications
You must be signed in to change notification settings - Fork 0
/
IntegerUtils.hs
108 lines (94 loc) · 2.73 KB
/
IntegerUtils.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
module IntegerUtils (
pow2,
msb,
lsb,
splitAtBit,
splitAtDigit,
base10len,
bitlen,
) where
import Prelude
import Data.Bits
import Math.NumberTheory.Logarithms
pow2 :: Integer -> Integer
pow2 n = shiftL 1 (fromInteger n)
-- Get most significant bits b of integer n
msb :: Integer -> Integer -> Integer
msb n b = shiftR n (fromInteger ((bitlen n)-b))
-- Get least significant bits b of integer n
lsb :: Integer -> Integer -> Integer
lsb n b = (toInteger . fromInteger) ((.&.) n ((shiftL 1 (fromInteger b)-1)))
-- Split an integer 'n' into high and low bits at [.. b+1],[b ..]
splitAtBit :: Integer -> Integer -> (Integer, Integer)
splitAtBit n b =
let l = lsb n b
h = msb n $ b+1
in (h, l)
splitAtDigit :: Integer -> Integer -> (Integer, Integer)
splitAtDigit n d =
let l = rem n $ 10^d
h = quot n $ 10^d
in (h, l)
base10len :: Integer -> Integer
base10len n = (+1) $ (toInteger (integerLog10 n))
-- Math.NumberTheory.Logarithms.integerLog2 solution is fastest
bitlen :: Integer -> Integer
bitlen = toInteger . (+1) . integerLog2
-- Fast - log log n solution - log2 (# of bits)
-- Recursivelly reach ahead 2^2^i until overshoot, count 2^2^(i-1),
-- continue recursively 2^2^(i=0) with new # minus the first
-- counted 2^2^(i-1) bits
bitlen_shoot :: Integer -> Integer
bitlen_shoot n = iter n 0 where
iter 1 0 = 1
iter n c
| scaled < n = iter n $ c+1
| scaled == n = (+1) . pow2 $ c
| scaled > n = lsb_count + iter msb_left 0
where
scale f = pow2 . pow2 $ f
scaled = scale c
lsb_count = pow2 $ c-1
msb_left = shiftR n . fromInteger . pow2 $ c-1
-- Very fast - same as bitlen but with no bit shifting
bitlen_pow :: Integer -> Integer
bitlen_pow n = iter n 0 where
iter 1 0 = 1
iter n c
| scale c < n = iter n $ c+1
| scale c == n = 2^c+1
| scale c > n = 2^(c-1) + iter (div n (2^2^(c-1))) 0
where scale f = 2^2^f
-- Fast - test n against 2^i until overshoot then linear drift down
bitlen_drift :: Integer -> Integer
bitlen_drift n = up n 0 where
down n c =
if (shiftL 1 (fromIntegral c)) > n
then down n $ c-1
else c+1
up n c =
if (shiftL 1 (2^c)) < n
then up n $ c+1
else down n $ 2^c
-- Middle of the road - linear in number of bits
bitlen_lin :: Integer -> Integer
bitlen_lin n = iter n 1 where
iter n a
| b == n = a+1
| b > n = a
| b < n = iter n $ a+1
where b = shiftL 1 (fromIntegral a)
--Slow
bitlen_div :: Integer -> Integer
bitlen_div n = (iter 2 n) + 1 where
iter a b
| b == 1 = 0
| otherwise = 1 + iter a (b `div` a)
--Slowest
bitlen_exp :: Integer -> Integer
bitlen_exp n = iter n 1 where
iter n a
| b == n = a+1
| b > n = a
| b < n = iter n $ a+1
where b = 2^a