使用费马小定理的原始性测试

时间:2013-10-09 07:12:13

标签: c primality-test

代码:

void prime()    
{    
    int i,N;    
    scanf("%d",&N);    
    for(i=2;i<N;i++)            
    {    
        if (((i^(N-1))%N )==1);     
        else{    
            printf("not prime");   
            return;
        }     
    }    
    printf("prime");    
    return;    
}    

该程序基于Fermat关于素数的定理。 N是要作为素数进行测试的数字。该程序未显示'11'的正确结果。也许是因为我发现了一些错误。

4 个答案:

答案 0 :(得分:2)

如果这是伪代码
,您将遇到溢出 如果使用C代码,则使用^作为幂运算符无效。

使用大整数很快成为C中的问题。可以使用各种BigInt库。

使用大整数计算时,使用浮点具有挑战性。建议避免doublepow()

由于问题都是&gt; = 0,建议使用无符号整数。还使用可用的最大整数类型 - 通常为unsigned long long。由于溢出是一种真正的可能性,请检测它。

unsigned long long upower(unsigned i, unsigned N) {
  unsigned long long power = 1;
  if (i <= 1) return i;
  while (N-- > 0) {
    unsigned long long power_before = power;
    power *= i;
    if (power < power_before) {
      printf("Overflow\n");
      return 0;
    }
  }
  return power;
}

void prime() {
  unsigned i, N;
  scanf("%u", &N);
  for (i = 2; i < N; i++) {
    if ((upower(i, N - 1) % N) != 1) {
      printf("not prime");
      return;
    }
  }
  printf("prime");
  return;
}

代替大整数,Chinese remainder theorem 可能提供(upower(i, N - 1) % N) != 1的替代方案。

答案 1 :(得分:1)

如果我将你的代码读作伪代码,你就会溢出。

10^10大于2^31 -1,这是大多数int的最大值。你可以通过使用long来解决N=11这个问题,但这不会让你走得太远,你也会在某些时候开始溢出。

这个定理,至少表达方式,与有限长度的数字一起使用是非常不切实际的。

现在,如果您的代码是真实的C,请注意^表示XOR,而不是取幂。指数为pow()。感谢评论者指出这一点。

答案 2 :(得分:0)

这里可以应用模块化的数学规则和原则来表明为了计算

  

(i ^(N-1))%N,

你甚至不需要在第一时间计算i ^(N-1)。 您可以轻松地将(N-1)分解为 2 的权力。 让我们举个例子来说明一点。

假设我们的素性测试的主题,N = 58。

所以,

  

N - 1 = 57

57可以很容易地重写为:

  

57 = 1 + 8 + 16 + 32

,或者

  

57 = 2 ^ 0 + 2 ^ 3 + 2 ^ 4 + 2 ^ 5

因此,将此值替换为 N-1 ,我们需要计算

  

(i ^(2 ^ 0 + 2 ^ 3 + 2 ^ 4 + 2 ^ 5))%58

,或者

  

((i ^ 1)×(i ^ 8)×(i ^ 16)×(i ^ 32))%58

使用Modular Multiplication身份,可以改写为:

  

((i ^ 1)%58×(i ^ 8)%58×(i ^ 16)%58×(i ^ 32)%58)mod 58 ---(1)

请注意,

  

(i ^ 1)%58 = i%58

可以很容易地计算而不用担心任何溢出。

再次使用Modular Multiplication身份,我们知道

  

(i ^ 2)%58 =((i ^ 1)%58×(i ^ 1)%58)%58

用(i ^ 1)%58的值代替(i ^ 2)%58。

你可以继续这种方式,计算(i ^ 4)%58到(i ^ 32)%58。一旦完成,你最终可以替换(1)中的值,最终找到所需的值,非常有效地避免任何溢出。

请注意,其他modular exponientation技术也存在。这只是一个例子,展示了如何使用模块化数学技术来实现费马的小素性测试。

干杯!

答案 3 :(得分:0)

抱歉,请稍稍更改您的代码。使用BigInteger类,您可以非常快速地计算出更大的数字。但是,您可以使用此方法不是按顺序获取素数,而是测试是否有任何素数。

using System;
using System.Numerics;
                    
public class Program
{
    public static void Main()
    {
        Console.WriteLine(2);
        for(var i = 3; i < 100000; i+=2) 
        {
            if(BigInteger.ModPow(2, i , i) == 2)
                Console.WriteLine(i);
        }
    }
}

https://dotnetfiddle.net/nwDP7h

此代码包含以下数字时,将产生错误的结果。

https://oeis.org/a001567 https://oeis.org/a006935

要解决这些错误,您需要按如下方式编辑代码,并在这些数字中进行二进制搜索以测试数字是否为伪质数。

public static bool IsPrime(ulong number)
{
    return number == 2
        ? true
        : (BigInterger.ModPow(2, number, number) == 2
            ? (number & 1 != 0 && BinarySearchInA001567(number) == false)
            : false)
}

public static bool BinarySearchInA001567(ulong number)
{
    // Is number in list?
    // todo: Binary Search in A001567 (https://oeis.org/A001567) below 2 ^ 64
    // Only 2.35 Gigabytes as a text file http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html
}