我的作业是提供一个计算'x ^ y mod n'的函数 - 对于任何n< (sqrt maxint32)
所以我开始写这样做:
modPow :: Int -> Int -> Int -> Int
modPow x y n = (x `mod` n) ^ (y `mod` n) `mod` n
对于任何数量的n,似乎工作得很好,虽然我的下一个作业问题涉及使用x ^ n mod n = x(Camichael数字),但我永远无法让modPow工作。
所以我使用伪代码对mod进行了另一个modPow,来自维基百科:
modPow2 :: Int -> Int -> Int -> Int
modPow2 x y n
= loopmod 1 1
where
loopmod count total = if count > y
then total
else loopmod (count+1) ((total*x) `mod` n)
现在正确地为我的下一个问题产生正确答案,(x ^ n mod n = x) - 用于检查Camichael数字。
尽管如此,modPow2不能用于大量的'y'(STACK-OVERFLOW !!)
我如何调整modPow2,以便在y> gt的情况下不再获得stackoverflow 10,000(但仍小于maxint 32的squre - 大约46,000)
或者我的原始modPow是否有修复,所以它适用于x ^ n mod n = x? (我总是将560 561 561作为输入,它给了我1而不是560(561是一个卡迈克尔数,所以应该给560回来)
非常感谢。
答案 0 :(得分:6)
modPow
的公式错误,您不能只使用 y mod n 作为指数,否则会导致错误的结果。例如:
Prelude> 2^10
1024
Prelude> 2^10 `mod` 10
4
Prelude> 2^(10 `mod` 10) `mod` 10
1
要获得更好的modPow
功能,您可以使用x2n+1 = x2n ⋅ x
和x2n = xn ⋅ xn
,而对于乘法,您实际可以使用 mod
因素。
答案 1 :(得分:4)
你从哪里得到modPow
的公式?
(x ^ y) `mod` n
= ((x `mod` n) ^ (y `mod` φ n)) `mod` n
其中φ
is Euler's totient function。
答案 2 :(得分:3)
这可能是因为参数total
是懒惰计算的。
如果您使用GHC,则可以通过放置loopmod
total
来loopmod count !total = ...
。在论证前面,即
else if total == 0 then 0 else loopmod (count+1) ((total*x) `mod` n)
另一种方法是强制评估总数,如下:用
替换最后一行0*x
这不会改变语义(因为{{1}}无论如何都是0,所以提醒也必须为0)并且它会强制拥抱在每次递归中评估总数。
答案 3 :(得分:0)
如果您正在寻找实施(a ^ d mod n),那么
powM::Integer->Integer->Integer->Integer
powM a d n
| d == 0 = 1
| d == 1 = mod a n
| otherwise = mod q n where
p = powM ( mod ( a^2 ) n ) ( shiftR d 1 ) n
q = if (.&.) d 1 == 1 then mod ( a * p ) n else p