TF6PK6JDRLBRDRJVI7M4RWSJG5NK6SAMSYINXD6ZGSE7DL4ILTMAC
MCBWM3FBZPTBMBJM4QISAX45C2D75QGHWXPLAYMN3EXJJ2CV4ASAC
XL3UEJW5ODILLWT37VFOTWJG5J4YV4MTODD5BTREEC7ZFSYXQHZQC
TEWWDULPAUYV2VFT3LGUTXGVVDPFFTBRHXQVJAZT63D5Q2NLPS6QC
5CXVNGYMMIBKPFJFJK7T5HLMUAP2IE7UCFZBFZTY5DBJFRQHPP5QC
VRPOSMITS7VRSIJU6YNEBELCUBTHPMPJD6F6F5PE35R2KECS42KAC
ASGE7I4JJ3HTHHSQKVNL74ZVZQ6WTYX6M54FYKOUE4PCPRPUNSUQC
PMF36FUOINXVVNP5XW6ZOFPPWFBRK62O4VCX45NE4Y4GDPL2Z3BQC
WFOLCYCZVNRVCEWSDJR36BGSN6IKJ4CMISYCOWBLENMOP2JUTRIQC
L6TQHWB6JUMHD6KZR3RMO23UHQ2E37P2BAFZGDXBL5KWK2WWAIJQC
2Q7SZHYMAFCYLG5MROYQ4BJ7HDIASPLIZJP7SM7BNX4GESUCZXJQC
O6UAIBEXBNE2XMWQWU6YKGGRLDQFI364JMV6HCYCCI3LBQRD6RPQC
G25ET6HXYNPM2HJ2L76TGOLVV2LBDA3CIWCAN6SL2WKNTUG56RDQC
twoPowers :: (Num a, Bits a, Integral b) => a -> [b]
twoPowers 0 = []
twoPowers m =
(if m `testBit` 0 then (0 :) else id) . fmap (+ 1) $ twoPowers (m `shiftR` 1)
-- | Index of highest-order set bit, or -1 if there are none.
mult' :: Int -> Nimber -> Nimber -> Nimber
mult' _ 0 _ = 0
mult' _ _ 0 = 0
mult' _ 1 b = b
mult' _ a 1 = a
mult' m a b =
let semiD = bit (bit m - 1) -- semimultiple of D
s1 = a `shiftR` bit m -- a = a1D+a2
s2 = a .^. (s1 `shiftL` bit m)
t1 = b `shiftR` bit m -- b = b1D+b2
t2 = b .^. (t1 `shiftL` bit m)
c = mult' (m - 1) s2 t2
in ((mult' (m - 1) (s1 + s2) (t1 + t2) - c) `shiftL` bit m) + mult' (m - 1) (mult' (m - 1) s1 t1) semiD + c
mult' _ 0 _ = 0
mult' _ _ 0 = 0
mult' _ 1 t = t
mult' _ s 1 = s
mult' k s t =
let semiD = bit (bit k - 1) -- semimultiple of D
s1 = s `shiftR` bit k -- a = a1D+a2
s2 = s .^. (s1 `shiftL` bit k)
t1 = t `shiftR` bit k -- b = b1D+b2
t2 = t .^. (t1 `shiftL` bit k)
c = mult' (k-1) s2 t2
in ((mult' (k-1) (s1 + s2) (t1 + t2) - c) `shiftL` bit k) + mult' (k-1) (mult' (k-1) s1 t1) semiD + c
sqr' :: Int -> Nimber -> Nimber
sqr' _ 0 = 0
sqr' _ 1 = 1
sqr' m n =
let a = n `shiftR` bit m -- n = aD+b
aD = a `shiftL` bit m
b = n .^. aD
semiD = bit (bit m - 1) -- semimultiple of D
sqra = sqr' (m - 1) a
in sqra `shiftL` bit m + mult' (m - 1) sqra semiD + sqr' (m - 1) b
| otherwise = product . fmap snd . filter (testBit n . fst) . zip [0 ..] . take (1 + floorLog (n + 1)) $ iterate sqr x
| otherwise =
let m = floorLog @Int $ floorLog x
in product . fmap snd . filter (testBit n . fst) . zip [0 ..] . take (1 + floorLog (n + 1)) $ iterate (sqr' m) x