Mod Haskell作业

时间:2011-10-12 13:35:49

标签: haskell

我的作业是提供一个计算'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回来)

非常感谢。

4 个答案:

答案 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 ⋅ xx2n = 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 totalloopmod 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