首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >中国剩余定理Haskell

中国剩余定理Haskell
EN

Stack Overflow用户
提问于 2016-02-20 21:22:14
回答 2查看 1.3K关注 0票数 3

我需要用Haskell写一个或几个函数来解决中国剩余定理。需要用以下定义创建它:

代码语言:javascript
复制
crt :: [(Integer, Integer)] -> (Integer, Integer)

答案看起来就像

代码语言:javascript
复制
>crt [(2,7), (0,3), (1,5)]
(51, 105)

我想我有一个整体的想法,我只是没有写它的知识。我知道crt函数必须是递归的。我创建了一个帮助函数,将元组列表拆分为两个列表的元组:

代码语言:javascript
复制
crtSplit xs = (map fst xs, product(map snd xs))

在这个例子中,它给了我:

代码语言:javascript
复制
([2,0,1],105)

我想我需要知道的是为第一个列表中的每个元素创建一个列表。我怎么开始这么做?

EN

回答 2

Stack Overflow用户

发布于 2016-02-20 21:39:48

中国剩余定理有一个algebraic solution,基于x = r1 % m1x = r2 % m2可以简化为一个模方程,如果m1m2coprime的话。

要做到这一点,您需要知道什么是modular inverse,以及如何使用extended Euclidean algorithm有效地计算它。

如果把这些部分放在一起,就可以用right fold来解决中国剩余定理。

代码语言:javascript
复制
crt :: (Integral a, Foldable t) => t (a, a) -> (a, a)
crt = foldr go (0, 1)
    where
    go (r1, m1) (r2, m2) = (r `mod` m, m)
        where
        r = r2 + m2 * (r1 - r2) * (m2 `inv` m1)
        m = m2 * m1

    -- Modular Inverse
    a `inv` m = let (_, i, _) = gcd a m in i `mod` m

    -- Extended Euclidean Algorithm
    gcd 0 b = (b, 0, 1)
    gcd a b = (g, t - (b `div` a) * s, s)
        where (g, s, t) = gcd (b `mod` a) a

然后:

代码语言:javascript
复制
\> crt [(2,7), (0,3), (1,5)]
(51,105)
\> crt [(2,3), (3,4), (1,5)]  -- wiki example
(11,60)
票数 6
EN

Stack Overflow用户

发布于 2016-02-20 22:06:20

不用进入代数,你也可以用蛮力来解决这个问题。也许这就是你被要求做的事。

对于您的示例,为每个mod创建一个独立于其他两个模块的列表(上界将是mod的最小公共倍数,假设它们是作为前提条件的同素数,即105)。这三个列表应该有一个共同的元素,可以满足所有的约束条件。

代码语言:javascript
复制
m3 = [3,6,9,12,15,...,105]
m5 = [6,11,16,21,...,101]
m7 = [9,16,23,30,...,100]

您可以使用Data.Set找到这些列表的交集。现在,使用递归或折叠将此逻辑扩展到n个术语。

更新也许更简单的方法是定义一个过滤器,为模数创建一个具有固定余数的序列,并对给定的对反复应用

代码语言:javascript
复制
Prelude> let rm (r,m) = filter (\x -> x `mod` m == r)       

验证它是否有效,

代码语言:javascript
复制
Prelude> take 10 $ rm (1,5) [1..]                                               
[1,6,11,16,21,26,31,36,41,46]

现在,对于给定的示例,请重复使用它,

代码语言:javascript
复制
Prelude> take 3 $ rm (1,5) $ rm (0,3) $ rm (2,7) [1..]        
[51,156,261]

当然,我们只需要第一个元素,改为头。

代码语言:javascript
复制
Prelude> head $ rm (1,5) $ rm (0,3) $ rm (2,7) [1..]       
51

我们可以用折叠来概括

代码语言:javascript
复制
Prelude> head $ foldr rm [1..] [(1,5),(0,3),(2,7)]                            
51
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35529211

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档