|
Serwis Edukacyjny w I-LO w Tarnowie
Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2026 mgr Jerzy Wałaszek
|
ProblemNależy sprawdzić, czy liczba naturalna p jest liczbą pierwszą. |
Opisany w tym rozdziale algorytm testowania pierwszości (ang. primality testing algorithm) liczby naturalnej p został opracowany w roku 1975 przez Michaela O. Rabina na podstawie prac Gary'ego L. Millera. Udostępnia on szybką metodę sprawdzania pierwszości liczby z możliwością kontrolowania poziomu prawdopodobieństwa popełnienia błędu – jest to zatem metoda probabilistyczna, zwana testem Millera-Rabina (ang. the Rabin-Miller Probabilistic Primalty Algorithm).
Test Millera-Rabina oparty jest na następującym twierdzeniu:
Niech p będzie nieparzystą liczbą pierwszą zapisaną
jako
ad, a2d, a4d, …, a2^(r-1), a2^r(mod p)
kończy się liczbą 1. Co więcej, jeśli ad
nie przystaje modulo p do 1, to wyraz ciągu Millera-Rabina
bezpośrednio poprzedzający 1 jest równy
Jeśli liczba p przejdzie test, to jest albo pierwsza, albo
silnie pseudopierwsza przy podstawie a. Test Millera-Rabina daje złe
wyniki (p złożona) dla co najwyżej
W algorytmie testu Millera-Rabina wykorzystujemy procedury mnożenia i potęgowania modulo, które opisaliśmy w rozdziale o chińskim teście pierwszości. Test ten wykorzystują obecnie prawie wszystkie systemy kryptografii publicznej do testowania pierwszości dużych liczb potrzebnych przy generacji kluczy szyfrujących/deszyfrujących.
K01: d ← p-1 ; obliczamy s i d K02: s ← 0 K03: Dopóki d mod 2 = 0: ; usuwamy z p-1 dzielniki 2, wykonuj kroki K04…K05 ; zliczając je w s K04: s ← s+1 K05: d ← d div 2 K06: Dla i = 1, 2, …, n: ; wykonujemy n testów Millera-Rabina wykonuj kroki K07…K15 K07: a ← Losuj(2, p-2) ; losujemy bazę a K08: x ← ad mod p ; wyliczamy pierwszy wyraz ciągu Millera-Rabina K09: Jeśli (x = 1) ∨ (x = p-1), ; jeśli x nie spełnia warunku, to następny obieg pętli K06 ; wybieramy inne a K10: j ← 1 K11: Dopóki (j < s) ∧ (x ≠ p-1): ; rozpoczynamy generację kolejnych wykonuj kroki K12…K14 ; wyrazów ciągu Millera-Rabina K12: x ← x2 mod p ; obliczamy kolejny wyraz K13: Jeśli x = 1, ; tylko ostatni wyraz ciągu Millera-Rabina to idź do kroku K17 ; może mieć wartość 1! K14: j ← j+1 K15: Jeśli x ≠ p-1, ; przedostatni wyraz ciągu Millera-Rabina to idź do kroku K17 ; musi być równy p-1 K16: Pisz "TAK" i zakończ ; pętla wykonała n testów ; i zakończyła się naturalnie. K17: Pisz "NIE" i zakończ ; liczba p nie przeszła ; testów Millera-Rabina
|
Uwaga: Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich. |
| Program odczytuje z pierwszego
wiersza liczbę
p oraz ilość testów Millera-Rabina
n,
a w drugim wierszu wypisuje: TAK
– jeśli liczba
p
jest pierwsza z prawdopodobieństwem |
Pascal// Test Millera-Rabina
// Data: 6.04.2008
// (C)2020 mgr Jerzy Wałaszek
//---------------------------
program prg;
// 64 bitowy generator pseudolosowy
//---------------------------------
function Losuj(a, b : qword) : qword;
var w : qword;
i : integer;
begin
for i := 1 to 8 do
begin
w := w shl 8;
w := w or random(256);
end;
Losuj := a+(w mod (b-a));
end;
// Funkcja mnoży a i b mod n
//--------------------------
function MnozModulo(a, b, n : qword) : qword;
var m, w : qword;
begin
w := 0; m := 1;
while m <> 0 do
begin
if b and m <> 0 then
w := (w+a) mod n;
a := (a shl 1) mod n;
m := m shl 1;
end;
MnozModulo := w;
end;
// Funkcja oblicza a^e mod n
//--------------------------
function PotegujModulo(a, e, n : qword) : qword;
var m, p, w : qword;
begin
p := a; w := 1; m := 1;
while m <> 0 do
begin
if e and m <> 0 then
w := MnozModulo(w, p, n);
p := MnozModulo(p, p, n);
m := m shl 1;
end;
PotegujModulo := w;
end;
var a, d, p, x : qword;
i, j, s, n : integer;
t : boolean;
begin
randomize;
readln(p, n);
d := p-1;
s := 0;
while d mod 2 = 0 do
begin
inc (s); d := d div 2;
end;
t := true;
for i := 1 to n do
begin
a := Losuj(2, p-2);
x := PotegujModulo(a, d, p);
if(x = 1) or (x = p-1) then continue;
j := 1;
while(j < s) and (x <> p-1) do
begin
x := MnozModulo(x, x, p);
if x = 1 then
begin
t := false; break;
end;
inc(j);
end;
if not t then break;
if x <> p-1 then
begin
t := false; break;
end;
end;
if t then writeln('TAK')
else writeln('NIE');
end. |
C++// Test Millera-Rabina
// Data: 6.04.2008
// (C)2020 mgr Jerzy Wałaszek
//---------------------------
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef unsigned long long ulong;
// 64 bitowy generator pseudolosowy
//---------------------------------
ulong Losuj(ulong a,
ulong b)
{
ulong w;
int i;
for(i = 1; i <= 8; i++)
{
w <<= 8;
w |= rand() % 256;
}
return a+(w % (b-a));
}
// Funkcja mnoży a i b mod n
//--------------------------
ulong MnozModulo(ulong a,
ulong b,
ulong n)
{
ulong m, w;
w = 0;
for(m = 1; m; m <<= 1)
{
if(b & m) w = (w+a) % n;
a = (a << 1) % n;
}
return w;
}
// Funkcja oblicza a^e mod n
//--------------------------
ulong PotegujModulo(ulong a,
ulong e,
ulong n)
{
ulong m, p, w;
p = a; w = 1;
for(m = 1; m; m <<= 1)
{
if(e & m) w = MnozModulo(w, p, n);
p = MnozModulo(p, p, n);
}
return w;
}
int main()
{
ulong a, d, p, x;
int i, j, s, n;
bool t;
srand(time(NULL));
cin >> p >> n;
s = 0;
for(d = p-1; d % 2 == 0; s++) d /= 2;
t = true;
for(i = 1; i <= n; i++)
{
a = Losuj(2, p-2);
x = PotegujModulo(a, d, p);
if((x == 1) || (x == p-1)) continue;
for(j = 1; (j < s) && (x != p-1); j++)
{
x = MnozModulo(x, x, p);
if(x == 1)
{
t = false; break;
}
}
if(!t) break;
if(x != p-1)
{
t = false; break;
}
}
cout << (t ? "TAK": "NIE") << endl;
return 0;
} |
Basic' Test Millera-Rabina
' Data: 6.04.2008
' (C)2020 mgr Jerzy Wałaszek
'---------------------------
' 64 bitowy generator pseudolosowy
'---------------------------------
Function Losuj(Byval a As Ulongint, _
Byval b As Ulongint) _
As Ulongint
Dim w As Ulongint, i As Integer
For i = 1 To 8
w = w Shl 8
w = w Or Culngint(Rnd(1)*256)
Next
Losuj = a+(w Mod (b-a))
End Function
' Funkcja mnoży a i b mod n
'--------------------------
Function MnozModulo(Byval a As Ulongint, _
Byval b As Ulongint, _
Byval n As Ulongint) _
As Ulongint
Dim As Ulongint m, w
w = 0: m = 1
While m
If b And m Then w = (w+a) Mod n
a = (a Shl 1) Mod n
m = m Shl 1
Wend
MnozModulo = w
End Function
' Funkcja oblicza a^e mod n
'--------------------------
Function PotegujModulo(Byval a As Ulongint, _
Byval e As Ulongint, _
Byval n As Ulongint) _
As Ulongint
Dim As Ulongint m, p, w
p = a: w = 1: m = 1
While m
If e And m Then _
w = MnozModulo(w, p, n)
p = MnozModulo(p, p, n)
m = m Shl 1
Wend
PotegujModulo = w
End Function
Dim As Ulongint a, d, p, x
Dim As Integer i, j, s, n
Dim t As Byte
Randomize
Input p, n
d = p-1
s = 0
While d Mod 2 = 0
s += 1: d \= 2
Wend
t = 1
For i = 1 To n
a = Losuj(2, p-2)
x = PotegujModulo(a, d, p)
if(x = 1) Or (x = p-1) Then _
Continue For
j = 1
while(j < s) And (x <> p-1)
x = MnozModulo(x, x, p)
If x = 1 Then
t = 0: Exit While
End If
j += 1
Wend
If t = 0 Then Exit For
If x <> p-1 Then
t = 0: Exit For
End If
Next
If t = 1 Then
Print "TAK"
Else
Print "NIE"
End If
End
|
Python
(dodatek)# Test Millera-Rabina
# Data: 14.02.2024
# (C)2024 mgr Jerzy Wałaszek
# ---------------------------
import random
G = 2**64
# 64 bitowy generator pseudolosowy
# ---------------------------------
def losuj(a, b):
w = 0
for i in range(8):
w <<= 8
w |= int(random.random()*256)
return a+(w % (b-a))
# Funkcja mnoży a i b % n
# -----------------------
def mnoz_modulo(a, b, n):
w, m = 0, 1
while m < G:
if b & m: w = (w+a) % n
a = (a << 1) % n
m <<= 1
return w
# Funkcja oblicza a**e % n
# ------------------------
def poteguj_modulo(a, e, n):
p, w, m = a, 1, 1
while m < G:
if e & m:
w = mnoz_modulo(w, p, n)
p = mnoz_modulo(p, p, n)
m <<= 1
return w
random.seed(None, 2)
arr = input().split(" ")
p = int(arr[0])
n = int(arr[1])
d, s = p-1, 0
while not (d % 2):
s += 1
d //= 2
t = True
for i in range(n):
a = losuj(2, p-2)
x = poteguj_modulo(a, d, p)
if (x == 1) or (x == p-1):
continue
j = 1
while (j < s) and (x != p-1):
x = mnoz_modulo(x, x, p)
if x == 1:
t = False
break
j += 1
if not t: break
if x != p-1:
t = False
break
if t:
print("TAK")
else:
print("NIE")
|
| Wynik: |
9223372036854775783 20 TAK 9223372036854775787 1 NIE |
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2026 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.