所以我在试图将中国余数定理实现到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
应用于我从处理所有二进制文件中得到的整个数字。
希望这在某种程度上有意义。
提前谢谢。
除了用Haskell表示这一点的问题外,我在这里看到了两个与中国余数定理公式本身有关的简单数学问题:
- 您可能想要
minv big_m mi
,而不是minv mi big_m
- 你没有汇总术语表的功能。为此,您可以使用Haskell函数
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函数语法,@bhekliler指出您有错误。尽管元组在这里混淆了问题,但普通的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