📜  原始性测试|套装2(Fermat方法)

📅  最后修改于: 2021-04-25 00:53:10             🧑  作者: Mango

给定数字n,检查它是否为质数。我们已经介绍和讨论了Set 1中用于素数测试的School方法。
原始性测试|第一组(介绍和学校方法)
在这篇文章中,讨论了费马方法。该方法是一种概率方法,基于Fermat的Little定理。

Fermat's Little Theorem:
If n is a prime number, then for every a, 1 < a < n-1,

an-1 ≡ 1 (mod n)
 OR 
an-1 % n = 1 
 

Example: Since 5 is prime, 24 ≡ 1 (mod 5) [or 24%5 = 1],
         34 ≡ 1 (mod 5) and 44 ≡ 1 (mod 5) 

         Since 7 is prime, 26 ≡ 1 (mod 7),
         36 ≡ 1 (mod 7), 46 ≡ 1 (mod 7) 
         56 ≡ 1 (mod 7) and 66 ≡ 1 (mod 7) 

Refer this for different proofs.

如果给定的数字是质数,则此方法始终返回true。如果给定的数字是合成数(或非素数),则它可能返回true或false,但是为合成数生成错误结果的可能性很低,并且可以通过执行更多迭代来降低。

下面是算法:

// Higher value of k indicates probability of correct
// results for composite inputs become higher. For prime
// inputs, result is always correct
1)  Repeat following k times:
      a) Pick a randomly in the range [2, n - 2]
      b) If gcd(a, n) ≠ 1, then return false
      c) If an-1 ≢ 1 (mod n), then return false
2) Return true [probably prime].

下面是上述算法的实现。该代码使用了模幂的幂函数

C++
// C++ program to find the smallest twin in given range
#include 
using namespace std;
 
/* Iterative Function to calculate (a^n)%p in O(logy) */
int power(int a, unsigned int n, int p)
{
    int res = 1;      // Initialize result
    a = a % p;  // Update 'a' if 'a' >= p
 
    while (n > 0)
    {
        // If n is odd, multiply 'a' with result
        if (n & 1)
            res = (res*a) % p;
 
        // n must be even now
        n = n>>1; // n = n/2
        a = (a*a) % p;
    }
    return res;
}
 
/*Recursive function to calculate gcd of 2 numbers*/
int gcd(int a, int b)
{
    if(a < b)
        return gcd(b, a);
    else if(a%b == 0)
        return b;
    else return gcd(b, a%b); 
}
 
// If n is prime, then always returns true, If n is
// composite than returns false with high probability
// Higher value of k increases probability of correct
// result.
bool isPrime(unsigned int n, int k)
{
   // Corner cases
   if (n <= 1 || n == 4)  return false;
   if (n <= 3) return true;
 
   // Try k times
   while (k>0)
   {
       // Pick a random number in [2..n-2]       
       // Above corner cases make sure that n > 4
       int a = 2 + rand()%(n-4); 
 
       // Checking if a and n are co-prime
       if (gcd(n, a) != 1)
          return false;
  
       // Fermat's little theorem
       if (power(a, n-1, n) != 1)
          return false;
 
       k--;
    }
 
    return true;
}
 
// Driver Program to test above function
int main()
{
    int k = 3;
    isPrime(11, k)?  cout << " true\n": cout << " false\n";
    isPrime(15, k)?  cout << " true\n": cout << " false\n";
    return 0;
}


Java
// Java program to find the
// smallest twin in given range
 
import java.io.*;
import java.math.*;
 
class GFG {
     
    /* Iterative Function to calculate
    // (a^n)%p in O(logy) */
    static int power(int a,int n, int p)
    {
        // Initialize result
        int res = 1;
         
        // Update 'a' if 'a' >= p
        a = a % p;
     
        while (n > 0)
        {
            // If n is odd, multiply 'a' with result
            if ((n & 1) == 1)
                res = (res * a) % p;
     
            // n must be even now
            n = n >> 1; // n = n/2
            a = (a * a) % p;
        }
        return res;
    }
     
    // If n is prime, then always returns true,
    // If n is composite than returns false with
    // high probability Higher value of k increases
    //  probability of correct result.
    static boolean isPrime(int n, int k)
    {
    // Corner cases
    if (n <= 1 || n == 4) return false;
    if (n <= 3) return true;
     
    // Try k times
    while (k > 0)
    {
        // Pick a random number in [2..n-2]    
        // Above corner cases make sure that n > 4
        int a = 2 + (int)(Math.random() % (n - 4));
     
        // Fermat's little theorem
        if (power(a, n - 1, n) != 1)
            return false;
     
        k--;
        }
     
        return true;
    }
     
    // Driver Program
    public static void main(String args[])
    {
        int k = 3;
        if(isPrime(11, k))
            System.out.println(" true");
        else
            System.out.println(" false");
        if(isPrime(15, k))
            System.out.println(" true");
        else
            System.out.println(" false");
             
    }
}
 
// This code is contributed by Nikita Tiwari.


Python3
# Python3 program to find the smallest
# twin in given range
import random
 
# Iterative Function to calculate
# (a^n)%p in O(logy)
def power(a, n, p):
     
    # Initialize result
    res = 1
     
    # Update 'a' if 'a' >= p
    a = a % p 
     
    while n > 0:
         
        # If n is odd, multiply
        # 'a' with result
        if n % 2:
            res = (res * a) % p
            n = n - 1
        else:
            a = (a ** 2) % p
             
            # n must be even now
            n = n // 2
             
    return res % p
     
# If n is prime, then always returns true,
# If n is composite than returns false with
# high probability Higher value of k increases
# probability of correct result
def isPrime(n, k):
     
    # Corner cases
    if n == 1 or n == 4:
        return False
    elif n == 2 or n == 3:
        return True
     
    # Try k times
    else:
        for i in range(k):
             
            # Pick a random number
            # in [2..n-2]     
            # Above corner cases make
            # sure that n > 4
            a = random.randint(2, n - 2)
             
            # Fermat's little theorem
            if power(a, n - 1, n) != 1:
                return False
                 
    return True
             
# Driver code
k = 3
if isPrime(11, k):
  print("true")
else:
  print("false")
   
if isPrime(15, k):
  print("true")
else:
  print("false")
 
# This code is contributed by Aanchal Tiwari


C#
// C# program to find the
// smallest twin in given range
using System;
class GFG {
     
    /* Iterative Function to calculate
    // (a^n)%p in O(logy) */
    static int power(int a,int n, int p)
    {
        // Initialize result
        int res = 1;
          
        // Update 'a' if 'a' >= p
        a = a % p;
      
        while (n > 0)
        {
            // If n is odd, multiply 'a' with result
            if ((n & 1) == 1)
                res = (res * a) % p;
      
            // n must be even now
            n = n >> 1; // n = n/2
            a = (a * a) % p;
        }
        return res;
    }
      
    // If n is prime, then always returns true,
    // If n is composite than returns false with
    // high probability Higher value of k increases
    //  probability of correct result.
    static bool isPrime(int n, int k)
    {
        // Corner cases
        if (n <= 1 || n == 4) return false;
        if (n <= 3) return true;
          
        // Try k times
        while (k > 0)
        {
            // Pick a random number in [2..n-2]    
            // Above corner cases make sure that n > 4
            Random rand = new Random();
            int a = 2 + (int)(rand.Next() % (n - 4));
          
            // Fermat's little theorem
            if (power(a, n - 1, n) != 1)
                return false;
          
            k--;
        }
      
        return true;
    }
     
  static void Main() {
        int k = 3;
        if(isPrime(11, k))
            Console.WriteLine(" true");
        else
            Console.WriteLine(" false");
        if(isPrime(15, k))
            Console.WriteLine(" true");
        else
            Console.WriteLine(" false");
  }
}
 
// This code is contributed by divyesh072019


PHP
= p
    $a = $a % $p;
 
    while ($n > 0)
    {
         
        // If n is odd, multiply
        // 'a' with result
        if ($n & 1)
            $res = ($res * $a) % $p;
 
        // n must be even now
        $n = $n >> 1; // n = n/2
        $a = ($a * $a) % $p;
    }
    return $res;
}
 
// If n is prime, then always
// returns true, If n is
// composite than returns
// false with high probability
// Higher value of k increases
// probability of correct
// result.
function isPrime($n, $k)
{
     
    // Corner cases
    if ($n <= 1 || $n == 4)
    return false;
    if ($n <= 3)
    return true;
     
    // Try k times
    while ($k > 0)
    {
         
        // Pick a random number
        // in [2..n-2]
        // Above corner cases
        // make sure that n > 4
        $a = 2 + rand() % ($n - 4);
     
        // Fermat's little theorem
        if (power($a, $n-1, $n) != 1)
            return false;
     
        $k--;
    }
 
    return true;
}
 
// Driver Code
$k = 3;
$res = isPrime(11, $k) ? " true\n": " false\n";
echo($res);
 
$res = isPrime(15, $k) ? " true\n": " false\n";
echo($res);
 
// This code is contributed by Ajit.
?>


输出:

true
false

该解决方案的时间复杂度为O(k Log n)。请注意,幂函数需要O(Log n)时间。
请注意,即使我们增加迭代次数(较高的k),上述方法也可能会失败。存在一些具有以下性质的复合数字:a n- 1≡1(mod n) 。这样的数字称为卡迈克尔数字。如果需要使用快速方法进行过滤,例如在RSA公钥密码算法的密钥生成阶段,通常会使用Fermat的素数测试。

我们很快将讨论更多的原始性测试方法。