【问题标题】:Can someone explain this Miller-Rabin Primality test pseudo-code in simple terms?有人可以简单地解释一下这个 Miller-Rabin Primality 测试伪代码吗?
【发布时间】:2013-06-08 11:05:48
【问题描述】:

这里是……

Input: n > 3, an odd integer to be tested for primality;
Input: k, a parameter that determines the accuracy of the test
Output: composite if n is composite, otherwise probably prime
Write n − 1 as (2^s)·d with d odd by factoring powers of 2 from n − 1
WitnessLoop: repeat k times:
   pick a random integer a in the range [2, n − 2]
   x ← a^d mod n
   if x = 1 or x = n − 1 then do next WitnessLoop
   repeat s − 1 times:
      x ← x^2 mod n
      if x = 1 then return composite
      if x = n − 1 then do next WitnessLoop
   return composite
return probably prime

我从Miller-Rabin primality test 上的维基百科文章中得到这个。但我一直无法理解它......我不想理解它背后的数学,而只是在程序中实现它。在我看来,这个算法有点令人困惑。更好、更简单的伪代码或在 vb.net 中的实现会有所帮助。

EDIT到目前为止编写的代码:

Function Miller_Rabin(ByVal n As Integer) As Boolean
    If n <= 3 Then : Return True
    ElseIf n Mod 2 = 0 Then : Return False
    Else
        Dim k, s, a, d, x As Integer
        k = 3
        d = n - 1

        While d Mod 2 = 0
            d = d / 2
            s += 1
        End While

        For c = 1 To k
            a = Random(2, n - 1)
            x = a ^ d Mod n
            If x = 1 Or x = n - 1 Then GoTo skip
            For r = 1 To s - 1
                x = x ^ 2 Mod n
                If x = 1 Then
                    Return False
                    Exit Function
                Else
                    If x = n - 1 Then
                        GoTo skip
                    Else
                        Return False
                        Exit Function
                    End If
                End If
            Next
skip:   Next
        Return True
    End If
End Function

Function Random(ByVal x As Integer, ByVal n As Integer) As Integer
    Dim a As Integer = Now.Millisecond * Now.Second
skip:
    a = (a ^ 2 + 1) Mod (n + 1)
    If a < x Then
        GoTo skip
    Else
        Return a
    End If
End Function

【问题讨论】:

  • 有一个VB6 implementation here 是否容易移植到 VB.NET?
  • 这太复杂了......你不能给我一个合适的伪代码吗?
  • 您从wiki发布的伪代码一点也不复杂,您遇到了什么问题?如果您编写了一些代码,也许可以编辑您的问题,以便我们可以看到您卡在哪里。只有在涉及非常大的数字时(大多数情况下),实现才会很痛苦。
  • 好的,请稍等.. 给我几分钟..
  • 这是我写的代码...link

标签: vb.net algorithm primes pseudocode primality-test


【解决方案1】:

这里是简单的伪代码,根据要求:

function isStrongPseudoprime(n, a)
    d := n - 1; s := 0
    while d % 2 == 0
        d := d / 2
        s := s + 1
    t := powerMod(a, d, n)
    if t == 1 return ProbablyPrime
    while s > 0
        if t == n - 1
            return ProbablyPrime
        t := (t * t) % n
        s := s - 1
    return Composite

function isPrime(n)
    for i from 1 to k
        a := randInt(2, n-1)
        if isStrongPseudoprime(n, a) == Composite
            return Composite
    return ProbablyPrime

function powerMod(b, e, m)
    x := 1
    while e > 0
        if e % 2 == 1
            x := (b * x) % m
        b := (b * b) % m
        e := e // 2 # integer division
    return x

isStrongPseudoprime 函数测试 a 是否是 n 复合性的见证;请注意,如果isStrongPseudoprime 返回Composite,则该数字肯定是复合数字,但与之相反的是ProbablyPrime,因为该数字仍有可能是复合数字。 isPrime 函数测试 k 个见证人;通过设置 k 的值,您可以将错误的可能性确定为 4^k 中的 1 次机会。大多数人使用的值 k 介于 10 到 25 之间。powerMod 函数通过平方来执行幂运算,并且在您的语言不提供它的情况下提供。

如果您想了解有关此测试背后的数学的更多信息,我在我的博客中谦虚地推荐 essay,其中还包括五种语言的实现,尽管它们都不是 VBA。

编辑:虽然他没有这么说,但原始发布者实际上想要做的是找到小于 200 万的素数之和,从而解决 Project Euler 10。循环从 2 到 n 是对小于 n 的素数求和的一种非常低效的方法;相反,推荐的方法是使用筛子。再次伪代码:

function sumPrimes(n)
    sum := 0
    sieve := makeArray(2..n, True)
    for p from 2 to n step 1
        if sieve[p]
            sum := sum + p
            for i from p * p to n step p
                sieve[i] := False
    return sum

这里使用的算法是两千多年前由一位希腊数学家发明的埃拉托色尼筛法。同样,解释和代码在我博客的essay 中。

【讨论】:

  • 我已经实现了它并且它可以工作......除非我使用任意精确的整数来确定大数是否是素数,它不起作用!像 1298074214633706835075030044377087 实际上是素数,但函数将它作为复合返回!
  • 我可以确认您所说的数字是质数。也许你有一些中间值溢出。程序中的所有变量都是大整数吗?
  • 我设法解决了这个问题......如果我让你为我测试你的实现会不会太麻烦?......我想知道下面所有素数的总和200 万,因为我的答案不断变化。
  • 我展示的解决方案是伪代码,无法运行。我提到的文章有五种语言的实现,都经过测试并且工作正常。如果你想对小于 n 的素数求和,那么不是从 2 迭代到 n 并测试每个数字的素数,更好的算法是筛分。我会将其添加到上面给出的答案中,因为代码无法在注释中正确格式化。
  • 我知道它效率低下......我只需要一个例子来测试我的实现......顺便说一句,你的文章涵盖了我所知道的语言以外的基于数学的函数,即c++ 和 vb.net。因此,我从某个站点获得了帮助,并使其正常运行。所以无论如何感谢您的帮助。 :D
【解决方案2】:

关键思想和概念(p在这里代表素数)

  1. 费马小定理。 ( a^(p-1) = 1 ( mod p ))
  2. 如果 p 是素数且 x^2 = 1 ( mod p ),则 x = +1 或 -1 ( mod p )。

我们可以证明如下:

x^2 = 1 ( mod p )
x^2 - 1 = 0 ( mod p )
(x-1)(x+1) = 0 ( mod p )

现在如果 p 不能同时整除 (x-1) 和 (x+1) 并且整除它们的乘积,那么它不可能是素数,这是矛盾的。因此,p 将除 (x-1) 或除 (x+1),因此 x = +1 或 -1 ( mod p )。

让我们假设 p - 1 = 2^d * s 其中 s 是奇数并且 d >= 0。如果 p 是素数,那么在这种情况下,无论是 as = 1 ( mod p ),从 as will 重复平方总是产生 1,所以 (a^(p-1))%p 将是 1;或 a^(s*(2^r)) = -1 ( mod p ) 对于某些 r 使得 0

算法:

  1. 设 p 是我们必须测试素数的给定数字。
  2. 首先我们将 p-1 重写为 (2^d)*s。 (其中 s 为奇数,d >= 0)。
  3. 现在我们在 [1,n-1] 范围内选择一些 a,然后检查是 as = 1 ( mod p ) 还是 a^(s*(2^r)) = -1 ( mod p )。李>
  4. 如果两者都失败,那么 p 肯定是复合的。否则 p 可能是素数。我们可以选择另一个 a 并重复相同的测试。
  5. 我们可以在一些固定次数的迭代后停止并声明 p 肯定是合数,或者它可能是素数。

小代码: Miller-Rabin素数检验,迭代表示检验的准确性

bool Miller(long long p,int iteration)
{
    if(p<2)
        return false;

    if(p!=2 && p%2==0){
                return false;

        long long s=p-1;
        while(s%2==0)
        {
                s/=2;
        }
        for(int i=0;i<iteration;i++)
        {
                long long a=rand()%(p-1)+1;
            long long temp=s;
                long long mod=modulo(a,temp,p);
                while(temp!=p-1 && mod!=1 && mod!=p-1)
            {
                    mod=mulmod(mod,mod,p);
                    temp *= 2;
                }
                if(mod!=p-1 && temp%2==0)
             {
                    return false;
                }
         }
         return true;
}

关于性能的几点:

可以证明,对于任何合数 p,当在上述测试中选择为“a”时,至少有 (3/4) 的小于 p 的数将证明 p 是合数。这意味着如果我们进行 1 次迭代,则复合数作为素数返回的概率为 (1/4)。对于 k 次迭代,测试失败的概率为 (1/4)k 或 4(-k)。与 Fermat 的测试相比,此测试相对较慢,但它不会分解任何特定的合数,并且 18-20 次迭代对于大多数应用程序来说是一个相当不错的选择。

PS:此函数计算 (a*b)%c 时考虑到 a*b 可能会溢出,我在 MILLER RABBIN 测试中使用了以上。

   long long mulmod(long long a,long long b,long long c)
   {
       long long x = 0,y=a%c;
       while(b > 0)
       {
          if(b%2 == 1)
          {
              x = (x+y)%c;
          }
          y = (y*2)%c;
          b /= 2;
       }
       return x%c;
    }

【讨论】:

  • 如果您有任何问题,请在评论中提出任何问题!
  • 我试图在 vb.net 中实现你的代码.....但是没有成功!这是它的链接...pastebin.com/utV5u7Lm
  • 我不知道 vb.net。但这肯定会在 C++ 上运行。我在编程中使用了这个实现!
  • @Will Ness- 感谢您的编辑.. 我一直在为代码缩进而苦苦挣扎!
  • 不客气。 :) 要缩进/取消缩进,选择一个段落并按 Ctrl-K(或按编辑区域上方的“代码”按钮)。
【解决方案3】:

VB 实现在模幂运算之前使用十六进制转换函数来处理大数。 cmets中提供的示例:

' USAGE:
' Example: strResult = mpModExp("3c", "03", "face")
' computes (0x3c)^3 mod 0xface = 0x5b56
' or, in decimal, 60^3 mod 64206 = 23382
' Parameters may be hex strings of any length subject to limitations
' of VB and your computer. May take a long time!

【讨论】:

    猜你喜欢
    • 2012-06-29
    • 1970-01-01
    • 2018-07-02
    • 1970-01-01
    • 2011-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多