中国剩余定理哈斯克尔

时间:2016-02-20 21:22:14

标签: haskell recursion chinese-remainder-theorem

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

.directive('fileUpload', ['$http', '$parse', function ($http, $parse) {
    return {
        restrict: 'A',

        link: function (scope, element, attrs, controller) {

            //for testing purpose. need to be removed.
            console.log('attachment type on file upload directive: ' + attrs.attachmentType)
            console.log('attachment id on file upload directive: ' + attrs.attachmentId)

            element.bind('click', function () {
                // Create the formdata and get the file
                var file = document.getElementById("inpFile").files[0];
                var formdata = new FormData();
                formdata.append('uploadedFile', file);

                ajaxUrl = root + 'FileUpload/upload?' & 'Type=' & attrs.attachmentType & 'ID=' & attrs.attachmentId;
                $http.post(ajaxUrl, formdata, {
                    headers: { "Content-Type": undefined }
                })
                .success(function (status) {
                    if (status.Succeed) {
                        alert('File Uploaded successfully.');
                    }
                    else {
                        alert(status.Err);
                    }
                    });
            });
        }
    };
}])

答案看起来像是

crt :: [(Integer, Integer)] -> (Integer, Integer)

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

>crt [(2,7), (0,3), (1,5)]
(51, 105)

在这个例子中,给了我:

crtSplit xs = (map fst xs, product(map snd xs))

我认为我需要知道的是为第一个列表中的每个元素创建一个列表。我将如何开始这样做?

2 个答案:

答案 0 :(得分:2)

中国余数定理有一个algebraic solution,基于x = r1 % m1x = r2 % m2如果m1m2可以简化为一个模块等式的事实coprime

为此,您需要了解modular inverse是什么以及如何使用extended Euclidean algorithm高效计算。

如果你将这些部分放在一起,你可以用right fold

来解决中文余数定理
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

然后:

\> crt [(2,7), (0,3), (1,5)]
(51,105)
\> crt [(2,3), (3,4), (1,5)]  -- wiki example
(11,60)

答案 1 :(得分:1)

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

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

m3 = [3,6,9,12,15,...,105]
m5 = [6,11,16,21,...,101]
m7 = [9,16,23,30,...,100]

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

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

Prelude> let rm (r,m) = filter (\x -> x `mod` m == r)       

验证它是否有效,

Prelude> take 10 $ rm (1,5) [1..]                                               
[1,6,11,16,21,26,31,36,41,46]

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

Prelude> take 3 $ rm (1,5) $ rm (0,3) $ rm (2,7) [1..]        
[51,156,261]

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

Prelude> head $ rm (1,5) $ rm (0,3) $ rm (2,7) [1..]       
51

我们可以用fold来概括

Prelude> head $ foldr rm [1..] [(1,5),(0,3),(2,7)]                            
51