Haskell实现中国剩余定理的问题

时间:2014-09-24 01:45:09

标签: haskell crt

所以我在尝试将中国剩余定理实现到Haskell时遇到了问题。到目前为止,我有这个:

minv :: Integer -> Integer -> Integer
minv a m = let (1, x, _) = extGCD a m
           in x `mod` m


crt :: [Integer] -> [Integer] -> Integer
crt as ms = let
                    prod = product ms
                    big_m = [div prod i| i <- ms]
            in (zip as ms (\(ai,mi)) ((ai * big_m * (minv mi big_m)) `mod` prod))

好的,所以我知道minv函数有效(我已多次测试过),但我无法使crt函数正常工作。所以这就是我想要做的事情:

我需要将列表asms压缩在一起,然后将每个二进制文件应用到实际找到中国剩余定理的等式中。但是我需要先处理二进制文件,然后将`mod` prod应用于我从所有二进制文件中获得的整数。

希望这有某种意义。

提前致谢。

1 个答案:

答案 0 :(得分:6)

除了你的问题表达为Haskell之外,我在这里看到两个与中国剩余定理公式本身相关的简单数学问题:

  1. 您可能需要minv big_m mi,而不是minv mi big_m
  2. 您无法总结术语列表。为此,您可以使用Haskell函数sum
  3. 因此,您首先要将表达式ai * big_m * (minv big_m mi)应用于列表asms中的每对元素。明确将其定义为命名函数非常有用,我们将其称为term

        term ai mi = ai * big_m * (minv big_m mi)
    

    (注意我aimi放在一个元组中,因为我们稍后用来压缩的函数不会使用它们。)

    但是,您定义big_m的方式不是数字,而是列表

        big_m = [div prod i| i <- ms]
    

    您实际需要的big_m是该列表中与aimi匹配的特定元素,它等于div prod mi。由于这是mi的函数,因此最简单的方法是在term的定义中定义它:

        term ai mi = let big_m = div prod mi
                     in ai * big_m * (minv big_m mi)
    

    (我实际上自己更喜欢wherelet,但我已经决定使用let,因为你在问题中做了。)

    现在您需要将函数term应用于asms中的所有相应元素。您可以通过将zipmap函数相结合来修复原始方法,例如

    map (\(ai,mi) -> term ai mi) (zip as ms)
    

    注意lambda函数语法,@ bheklilr指出你错了。虽然元组在这里很复杂,但普通的lambda函数里面不需要括号,并且必须同时包含\->

    然而,Haskell有一个方便的函数zipWith,可以一次完成(并且不需要函数来获取元组):

    zipWith term as ms
    

    然后,您需要使用sum对这样构建的列表中的术语求和。

    sum (zipWith term as ms)
    

    最后,您现在可以将最终`mod` prod应用于此:

    sum (zipWith term as ms) `mod` prod
    

    结合所有这些,最终的crt功能可以成为

    crt :: [Integer] -> [Integer] -> Integer
    crt as ms = let
                    prod = product ms
                    term ai mi = let big_m = div prod mi
                                 in ai * big_m * (minv big_m mi)
                in sum (zipWith term as ms) `mod` prod