Liczby pierwsze - generacja liczb pierwszych

advertisement
Artykuł pobrano ze strony eioba.pl
Liczby pierwsze - generacja liczb pierwszych
Do generacji liczb pierwszych wykorzystamy podaną w poprzednim rozdziale definicję liczby
pierwszej. Algorytm będzie składał się z dwóch oddzielnych części. Pierwsza część bada, czy
przekazana jej liczba jest liczbą pierwszą. Druga typuje liczby pierwsze, przekazuje je do zbadania
pierwszej części i jeśli otrzyma pozytywną odpowiedź, wyprowadza je jako wynik. Takie podejście do
rozwiązania problemu ułatwi nam wprowadzanie optymalizacji w następnych wersjach algorytmu.
Funkcja Testuj ma za zadanie stwierdzenie, czy przekazana jej jako parametr liczba naturalna p jest
liczbą pierwszą. Tego typu zadanie nazywa się badaniem pierwszości liczby (ang. primality testing).
Dane wejściowe
p- badana liczba przekazana do funkcji Testuj jako parametr, p
N
Dane wyjściowe
Wynik logiczny true, jeśli liczba p jest liczbą pierwszą lub wynik false w przypadku przeciwnym. Wynik
stanowi wartość funkcji Testuj.
Zmienne pomocnicze
i- pełni rolę licznika pętli oraz kolejnych dzielników liczby p, i
krok 1:Dla i = 2,3,...,p - 1 jeśli (p mod i) = , to Testuj(p)
krok 2:Testuj(p)
true i zakończ algorytm
N
false i zakończ algorytm
Na początku algorytmu inicjujemy pętlę kontrolowaną przez zmienną i, która początkowo przyjmuje
wartość 2. Zmienna ta pełni również rolę kolejnych dzielników liczby p.
Pętla wykonuje się przy i mniejszym od p. W przeciwnym razie zostaje przerwana i algorytm kończy
się zwrotem wartości logicznej true (prawda), co oznacza, iż żadna liczba z przedziału od 2 do p - 1
nie dzieli p. Zatem p jest liczbą pierwszą.
Wewnątrz pętli sprawdzamy, czy dzielnik i dzieli bez reszty liczbę p. Jeśli tak, to pętla również ulega
przerwaniu i algorytm zwraca wartość logiczną false (fałsz) - liczba p nie jest pierwsza.
Jeśli reszta z dzielenia p przez i jest różna od 0, to zwiększamy i o 1 (bierzemy następny dzielnik) i
wracamy na początek pętli.
Posiadając funkcję testującą pierwszość możemy utworzyć główny algorytm generacji liczb
pierwszych. Algorytm ten będzie generował zadaną ilość początkowych liczb pierwszych.
Algorytm wykorzystuje poprzednio zdefiniowaną funkcję badania pierwszości liczby do generacji
kolejnych liczb pierwszych.
Dane wejściowe
ile- określa ilość początkowych liczb pierwszych, które należy wygenerować, ile
N
Dane wyjściowe
Kolejno znalezione liczby pierwsze pi , i = 1,2,3,...,ile.
Zmienne pomocnicze
lp- zlicza znalezione liczby pierwsze, lp
p - zawiera kolejno testowane liczby, p
N
N, p = 2,3,...
krok 1:Czytaj ile
krok 2:lp
; p
2
krok 3:Dopóki lp < ile wykonuj kroki 4...5. Inaczej zakończ algorytm.
krok 4: Jeśli Testuj(p) = true, to wypisz p i zwiększ lp
lp + 1
krok 5: Zwiększ p
p + 1 i kontynuuj pętlę od kroku 3
Najpierw odczytujemy ile liczb pierwszych ma znaleźć nasz algorytm. Informacja ta zostanie
umieszczona w zmiennej ile. Następnie inicjujemy licznik liczb pierwszych lp na 0 (nie znaleziono
jeszcze żadnej liczby pierwszej) oraz p na 2 (pierwsza możliwa liczba pierwsza).
Teraz rozpoczyna się pętla warunkowa, która jest kontynuowana przy warunku lp < ile. Warunek ten
będzie spełniony do momentu znalezienia zadanej ilości liczb pierwszych. Wtedy pętla zostanie
przerwana i algorytm zakończy swoje działanie.
Wewnątrz pętli wywołujemy funkcję Testuj z parametrem p. Funkcja ta zbada, czy przekazany jej
parametr jest liczbą pierwszą. Jeśli tak, to zwróci wartość logiczną true. W takim przypadku
wypiszemy p i zwiększymy o 1 licznik lp. Jeśli p nie jest liczbą pierwszą, to funkcja Testuj zwróci
wartość logiczną false. Wtedy pominiemy wypisanie p i zwiększenie o 1 licznika lp.
Pętla zawsze kończy się zwiększeniem o 1 liczby p, czyli przejściem do kolejnej wartości, która
potencjalnie może być liczbą pierwszą. Po tej operacji przechodzimy na początek pętli i cały opisany
cykl rozpoczyna się od nowa.
Poniższe, przykładowe programy są praktyczną realizacją omawianego w tym rozdziale
algorytmu. Zapewne można je napisać bardziej efektywnie. To już twoje zadanie. Dokładny
opis stosowanych środowisk programowania znajdziesz we wstępie. Programy przed
opublikowaniem w serwisie edukacyjnym zostały dokładnie przetestowane. Jeśli jednak
znajdziesz jakąś usterkę (co zawsze może się zdarzyć), to prześlij o niej informację do autora.
Pozwoli to ulepszyć nasze artykuły. Będziemy Ci za to wdzięczni.
Wydruk z uruchomionego programu
Generator zadanej ilości liczb pierwszych
----------------------------------------(C)2005 mgr Jerzy Wałaszek I LO Tarnów
Ile liczb wygenerować ? : 150
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
KONIEC, naciśnij ENTER.
Microsoft Visual Basic 2005 Express Edition
Borland
Delphi 7.0
Personal
Edition
// Program generacji liczb pierwszych
// (C)2004 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//----------------------------------program glp;
{$APPTYPE CONSOLE}
// Funkcja sprawdza, czy przekazana jako parametr
// liczba p jest liczbą pierwszą. Jeśli tak, to
// zwraca w wyniku true, przeciwnie zwraca false
//----------------------------------------------function Testuj(p : cardinal) : boolean;
var
i : cardinal;
begin
Testuj := true;
i := 2;
while i < p do
if p mod i = then
begin
Testuj := false; break;
end
else i := i + 1;
end;
//---------------------------------// Tutaj rozpoczynamy program główny
//---------------------------------var
ile,lp,p : cardinal;
begin
writeln('Generator zadanej ilosci liczb pierwszych');
writeln('-----------------------------------------');
writeln('(C)2004 mgr Jerzy Walaszek I LO Tarnow');
writeln;
write('Ile liczb wygenerowac ? : '); readln(ile);
writeln;
lp := ; p := 2;
while lp < ile do
begin
if Testuj(p) then
begin
write(p : 8);
lp := lp + 1;
end;
p := p + 1;
end;
writeln;
write('Klawisz Enter = KONIEC'); readln; writeln;
end.
Borland
C++ Builder
6.0
Personal
Edition
// Program generacji liczb pierwszych
// (C)2004 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//----------------------------------#include <iostream>
#include <iomanip>
using namespace std;
// Funkcja sprawdza, czy przekazana jako parametr
// liczba p jest liczbą pierwszą. Jeśli tak, to
// zwraca w wyniku 1, przeciwnie zwraca 0
//----------------------------------------------bool Testuj(unsigned p)
{
unsigned i = 2;
while(i < p) if(!(p % i++)) return false;
return true;
}
//---------------------------------// Tutaj rozpoczynamy program główny
//---------------------------------main()
{
unsigned ile,lp,p;
char s[1];
cout << "Generator zadanej ilosci liczb pierwszychn"
"-----------------------------------------n"
"(C)2004 mgr Jerzy Walaszek I LO Tarnownn"
"Ile liczb wygenerowac ? : ";
cin >> ile;
cout << endl;
lp = ; p = 2;
while(lp < ile)
{
if(Testuj(p))
{
cout << setw(8) << p; lp++;
}
p++;
}
cout << "nnKlawisz Enter = KONIEC";
cin.getline(s,1);
cin.getline(s,1);
}
Microsoft
Visual
Basic 2005
Express
Edition
' Program generacji liczb pierwszych
' (C)2005 mgr Jerzy Wałaszek
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'----------------------------------Option Explicit On
Module Module1
' Funkcja sprawdza, czy przekazana jako parametr
' liczba p jest liczbą pierwszą. Jeśli tak, to
' zwraca w wyniku true, przeciwnie zwraca false
'----------------------------------------------Public Function Testuj(ByVal p As UInteger) As Boolean
Dim i As UInteger
i=2
While i < p
If (p Mod i) = Then
Return False
Else
i += 1
End If
End While
Return True
End Function
Sub Main()
Dim ile, lp, p As UInteger
Console.WriteLine("Generator zadanej ilości liczb pierwszych")
Console.WriteLine("-----------------------------------------")
Console.WriteLine("(C)2005 mgr Jerzy Wałaszek I LO Tarnów")
Console.WriteLine()
Console.Write("Ile liczb wygenerować ? : ")
ile = Val(Console.ReadLine)
Console.WriteLine()
lp = : p = 2
While lp < ile
If Testuj(p) Then
Console.Write("{0,8}", p)
lp += 1
End If
p += 1
End While
Console.WriteLine()
Console.WriteLine("KONIEC, naciśnij ENTER.")
Console.ReadLine()
End Sub
End Module
Python
# -*- coding: cp1250 -*# Program generacji liczb pierwszych
# (C)2005 mgr Jerzy Wałaszek
# I Liceum Ogólnokształcące
# im. K. Brodzińskiego
# w Tarnowie
#----------------------------------# Funkcja sprawdza, czy przekazana jako parametr
# liczba p jest liczbą pierwszą. Jeśli tak, to
# zwraca w wyniku 1, przeciwnie zwraca 0
#----------------------------------------------def Testuj(p):
for i in range(2, p):
if p % i == : return False
return True
#---------------------------------# Tutaj rozpoczynamy program główny
#---------------------------------print "Generator zadanej ilosci liczb pierwszych"
print "-----------------------------------------"
print "(C)2005 mgr Jerzy Walaszek I LO Tarnow"
print
ile = int(raw_input("Ile liczb wygenerowac ? : "))
print
lp, p = , 2
while lp < ile:
if Testuj(p):
print "%7d" % p,
lp += 1
p += 1
print
print
raw_input("Klawisz Enter = KONIEC")
JavaScript <html>
<head>
</head>
<body>
<div align="center">
<form name="primes"
style="border: 1px outset #FF9933;
padding-left: 4px; padding-right: 4px;
padding-top: 1px; padding-bottom: 1px;
background-color: #FFCC66">
<h3 style="text-align: center">
Generator zadanej ilości liczb pierwszych
</h3>
<p style="text-align: center">
(C)2004 mgr Jerzy Wałaszek - I LO w Tarnowie
</p>
<hr>
<p style="text-align: center">
Ilość liczb pierwszych do wygenerowania
</p>
<p style="text-align: center">
<input type="text" name="T1" size="20" value="10">
</p>
<p style="text-align: center">
<input type="button" value="Generuj" name="B1" onclick="main()">
</p>
<p id="data_out" style="text-align: center">...</p>
</form>
<script language=javascript>
// Program generacji liczb pierwszych
// (C)2004 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//----------------------------------// Funkcja sprawdza, czy przekazana jako parametr
// liczba p jest liczbą pierwszą. Jeśli tak, to
// zwraca w wyniku 1, przeciwnie zwraca 0
//----------------------------------------------function Testuj(p)
{
var i;
i = 2;
while(i < p) if(!(p % i++)) return ;
return 1;
}
function main()
{
var s,ile,lp,p;
ile = parseInt(document.primes.T1.value);
if(isNaN(ile))
s = "<font color=Red><b>ZŁE DANE</b></font>";
else
{
lp = ; p = 2; s = "";
while(lp < ile)
{
if(Testuj(p))
{
s += p + " "; lp++;
}
p++;
}
}
document.getElementById("data_out").innerHTML = s;
}
</script>
</div>
</body>
</html>
Dla celów badawczych zbierzemy dane o ilości wykonywanych operacji modulo. Wyposażymy
program w odpowiedni licznik, którego stan będzie zwiększany każdorazowo przy wykonywaniu
operacji modulo. Na końcu wyświetlimy stan licznika. Oto konieczne modyfikacje programu w Delphi:
Na początku programu dopisujemy deklarację zmiennej lom - licznika operacji modulo. Ponieważ
liczba operacji modulo może przekraczać zakres typu cardinal (232 - 1), wybieramy rozszerzony typ
zmiennoprzecinkowy extended, który daje dokładność około 19...20 cyfr znaczących.
// Program generacji liczb pierwszych
// (C)2004 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//----------------------------------program glp;
{$APPTYPE CONSOLE}
var
lom : extended; // licznik operacji modulo
Druga zmiana polega na modyfikacji funkcji Testuj, aby w przy każdej operacji modulo następowało
zwiększenie o 1 licznika lom.
// Funkcja sprawdza, czy przekazana jako parametr
// liczba p jest liczbą pierwszą. Jeśli tak, to
// zwraca w wyniku true, przeciwnie zwraca false
//----------------------------------------------function Testuj(p : cardinal) : boolean;
var
i : cardinal;
begin
Testuj := true;
i := 2;
while i < p do
begin
lom := lom + 1; // Tutaj jest zmiana
if p mod i = then
begin
Testuj := false; break;
end
else
i := i + 1;
end;
end;
Trzecią zmianę wprowadzamy do programu głównego. Ma ona na celu zainicjowanie licznika lom na 0
przed rozpoczęciem zliczania operacji modulo oraz wyświetlenie jego stanu po wykonaniu zadania
przez program.
//---------------------------------// Tutaj rozpoczynamy program główny
//---------------------------------var
ile,lp,p : cardinal;
begin
writeln('Generator zadanej ilosci liczb pierwszych');
writeln('-----------------------------------------');
writeln('(C)2004 mgr Jerzy Walaszek I LO Tarnow');
writeln;
write('Ile liczb wygenerowac ? : '); readln(ile);
writeln;
lp := ; p := 2;
lom := 0;
// Tutaj jest zmiana
while lp < ile do
begin
if Testuj(p) then
begin
write(p : 8); lp := lp + 1;
end;
p := p + 1;
end;
writeln;
writeln('Liczba operacji modulo : ',lom:15:0); // Tutaj jest zmiana
writeln;
write('Klawisz Enter = KONIEC'); readln; writeln;
end.
Wyniki uzyskane w tak zmodyfikowanym programie zebraliśmy w poniższej tabeli.
Wyniki badania ilości wykonanych operacji modulo
Ilość
l. pierw.
10
100
1000
10000
100000
Ilość
op. modulo
134
24984
3711627
497007180
62284747034
Wzrost
186,448
148,560
133,905
125,320
W pierwszej kolumnie znajduje się ilość generowanych przez program liczb pierwszych. Ilość ta w
każdym wierszu tabeli wzrasta dziesięciokrotnie. Z uwagi na niską efektywność prezentowanego
algorytmu zakończyliśmy na liczbie 100000. Wyznaczenie tej ilości liczb pierwszych zajęło naszemu
komputerowi około 40 minut ciągłej pracy.
W drugiej kolumnie umieściliśmy ilość wykonanych przez program operacji modulo do wyznaczenia
zadanej ilości liczb pierwszych.
W trzeciej kolumnie obliczyliśmy przyrost wykonanych operacji modulo w dwóch sąsiednich wierszach
tabeli, np.:
24984 : 134 = 186,448
3711627 : 24984 = 148,560
497007180 : 3711627 = 133,905, itd.
Przeanalizuj dane zawarte w powyższej tabeli i wyciągnij wnioski na temat klasy złożoności
obliczeniowej prezentowanego w tym rozdziale algorytmu.
Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.
Autor: mgr Jerzy Wałaszek
Przedruk ze strony: http://www.i-lo.tarnow.pl/edu/inf/alg/primes/index.html
Artykuł pobrano ze strony eioba.pl
Download