1. 程式人生 > 實用技巧 >PRIME

PRIME

素數是數論的核心

整數p>1是素數,當且僅當它的因子只有±1和±p.

介紹算術基本定理

簡單copy一下:https://wenku.baidu.com/view/d0a116035acfa1c7ab00cc69.html


定理1:

證明:


定理2:

證明:

推論:

證明:


定理3:

證明:


定理4:(算術基本定理

這種表達是唯一的

證明:

推論1:

證明:

推論2:


費馬定理+尤拉定理(這裡不給出證明)


費馬定理:

  若p是素數,a是正整數且不能被p整除,則:

  ap-1≡ 1 (mod p)

尤拉函式Φ(n)

  Φ(n)是小於n且與n互素的正整數的個數。

尤拉定理:

  對於任何互素的a和n,有

  aΦ(n) ≡ 1 (mod n)


許多密碼演算法都需要隨機選擇一個或者多個非常非常大的素數。

我們需要有一種方法測定一個確定的數是否是素數。===> 素性測試 下面給出兩個方法 簡單的測試和Rabin-Miller演算法:

簡單的測試演算法:

# Prime Number Sieve
# http://inventwithpython.com/hacking (BSD Licensed)

import math


def isPrime(num):
    
# Returns True if num is a prime number, otherwise False. # Note: Generally, isPrime() is slower than primeSieve(). # all numbers less than 2 are not prime if num < 2: return False # see if num is divisible by any number up to the square root of num for i in range(2, int(math.sqrt(num)) + 1):
if num % i == 0: return False return True def primeSieve(sieveSize): # Returns a list of prime numbers calculated using # the Sieve of Eratosthenes algorithm. sieve = [True] * sieveSize sieve[0] = False # zero and one are not prime numbers sieve[1] = False # create the sieve for i in range(2, int(math.sqrt(sieveSize)) + 1): pointer = i * 2 while pointer < sieveSize: sieve[pointer] = False pointer += i # compile the list of primes primes = [] for i in range(sieveSize): if sieve[i] == True: primes.append(i) return primes
isPrime(num)   檢查給定的數是否能整除2~sqrt(num)之間的整數。而不必檢查2~num之間的所有整數。 primeSieve(sieveSize)   利用埃拉托色尼(Eratosthenes)篩選法   1.比如找50以內的的所有質數建立一個這樣的表,把每個數標記為質數:

  2.把1標記為非質數

  3.把所有2的倍數(除了2本身)標記為非質數

  4.把所有3的倍數(除了3本身)標記為非質數

  5.把所有4的倍數(除了4本身)標記為非質數

  重複該過程

  直到8為止(為什麼是8? 答:int(math.sqrt(50) = 8)

做完了這些,我們可以看到,表格中留白的都是質數。

但是這個簡單的演算法是有侷限性的,對於大的數時,就略顯乏力

著名的Rabin-Miller演算法:

背景:

n≥3的整奇數n可以表示為:

  n-1 = 2kq 其中:k>0, q是奇數,n-1是個偶數!

素數第一性質:

  若p是素數,a是小於p的正整數,則 a2 mod p = 1, 當且僅當

    a mod p = 1 或者 a mod p = -1 mod p = p -1

素數第二性質:

  設p是大於2的素數(p.s. 肯定是個奇數,滿足p-1 = 2kq,其中:k>0, q是奇數); 設a是整數且1<a<p-1,則必有下面兩個條件之一成立:

  • aq 模 p 和 1 同餘, 即 aqmod p = 1 或者說:aq≡ 1(mod p)
  • 整數aq, a2q, a4q, ... , a2^(k-1)·q中存在一個數, 模p時和-1同餘。

詳細的演算法

  1. 找出整數k, q, 其中 k>0, q是奇數, 使(n-1 = 2kq );
  2. 隨機選取整數a, 1<a<n-1;
  3. ifaqmod n = 1, then 返回 不確定;
  4. for j=0 to k-1 do:
  5.   if a2jq mod n = n-1 ,then 返回 不確定
  6. 返回"合數"

重複使用Rabin-Miller演算法:提高“不確定”的可信度

選擇多個(t)不同的整數a,他們都能通過測試(返回不確定)的概率小於(1/4)t p.s. 某篇論文證明的哈哈哈哈哈哈

因此,取足夠大的t,如果Miller測試總是返回“不確定”, 我們能以很大的把握說n是素數。

# Primality Testing with the Rabin-Miller Algorithm
# http://inventwithpython.com/hacking (BSD Licensed)

import random

# 測試是不是質數的演算法主體  .
def rabinMiller(num):
    # Returns True if num is a prime number.


    # 找出整數t, s, 其中 t>0, q是奇數, 使 n-1 = (2^t)*s ;
    s = num - 1
    t = 0
    while s % 2 == 0:
        # keep halving s until it is even (and use t
        # to count how many times we halve s)
        s = s // 2
        t += 1

    # 隨機選取整數a, 1<a<n-1;選擇不同的a的次數越多,就越準確地‘判斷’
    for trials in range(5): # try to falsify num's primality 5 times
        # random.randrange的函式原型為:random.randrange([start], stop[, step]),從指定範圍內,按指定基數遞增的集合中 獲取一個隨機數。
        a = random.randrange(2, num - 1)
        # 函式是計算 x 的 y 次方,如果 z 在存在,則再對結果進行取模,其結果等效於 pow(x,y) %z
        v = pow(a, s, num)
        # if a^s mod num = 1, then if不進入返回  一次   不確定;
        if v != 1: # this test does not apply if v is 1.
            i = 0
            
            while v != (num - 1):
                if i == t - 1:
                    return False
                else:
                    i = i + 1
                    v = (v ** 2) % num
    return True


def isPrime(num):
    # Return True if num is a prime number. This function does a quicker
    # prime number check before calling rabinMiller().

    if (num < 2):
        return False # 0, 1, and negative numbers are not prime

    # About 1/3 of the time we can quickly determine if num is not prime
    # by dividing by the first few dozen prime numbers. This is quicker
    # than rabinMiller(), but unlike rabinMiller() is not guaranteed to
    # prove that a number is prime.
    lowPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]

    if num in lowPrimes:
        return True

    # See if any of the low prime numbers can divide num
    for prime in lowPrimes:
        if (num % prime == 0):
            return False

    # If all else fails, call rabinMiller() to determine if num is a prime.
    return rabinMiller(num)


def generateLargePrime(keysize=1024):
    # Return a random prime number of keysize bits in size.
    while True:
        num = random.randrange(2**(keysize-1), 2**(keysize))
        if isPrime(num):
            return num