所以我在尝试将中国剩余定理实现到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
函数正常工作。所以这就是我想要做的事情:
我需要将列表as
和ms
压缩在一起,然后将每个二进制文件应用到实际找到中国剩余定理的等式中。但是我需要先处理二进制文件,然后将`mod` prod
应用于我从所有二进制文件中获得的整数。
希望这有某种意义。
提前致谢。
答案 0 :(得分:6)
除了你的问题表达为Haskell之外,我在这里看到两个与中国剩余定理公式本身相关的简单数学问题:
minv big_m mi
,而不是minv mi big_m
。sum
。因此,您首先要将表达式ai * big_m * (minv big_m mi)
应用于列表as
和ms
中的每对元素。明确将其定义为命名函数非常有用,我们将其称为term
:
term ai mi = ai * big_m * (minv big_m mi)
(注意我不将ai
和mi
放在一个元组中,因为我们稍后用来压缩的函数不会使用它们。)
但是,您定义big_m
的方式不是数字,而是列表
big_m = [div prod i| i <- ms]
您实际需要的big_m
是该列表中与ai
和mi
匹配的特定元素,它等于div prod mi
。由于这是mi
的函数,因此最简单的方法是在term
的定义中定义它:
term ai mi = let big_m = div prod mi
in ai * big_m * (minv big_m mi)
(我实际上自己更喜欢where
到let
,但我已经决定使用let
,因为你在问题中做了。)
现在您需要将函数term
应用于as
和ms
中的所有相应元素。您可以通过将zip
与map
函数相结合来修复原始方法,例如
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