Một phương pháp lập bảng số nguyên tố
Ngô Minh Đức
Trong bài viết này tôi xin giới thiệu một phương pháp lập bảng số nguyên tốkhác, ngoài
phương pháp sàng Eratosthenes đã qúa quen thuộc với cácbạn.
Xin nhắc lại về sàng Eratosthenes (mang tên nhà toán học Hy Lạp, 275 - 194 TCN):
- Ta sắp xếp các số tự nhiên từ 2 đến N vào một bảng theo thứ tự 2,3,4,5,... N.
- Lưu lại số 2, lần lượt xóa đi các bội số của 2.
- Sau số 2, số không bị xóa đầu tiên là số 3, lần lượt xóa đi các bội số của 3
- Sau số 3, số không bị xóa đầu tiên là số 5, lần lượt xóa đi các bội số của 5,...
- Lặp lại đến khi không thể xóa được nữa thì thôi
Như vậy các số không bị xóa lập thành bảng các số nguyên tố nhỏ hơn hoặc bằng N.
Trong bộ sách ″Câu Chuyện Toán Học″ (một bộ sách rất hay gồm 6 tập của các thầy
Nguyễn Bá Đô, Đỗ Mạnh Hùng và Nguyễn Văn Túc), tập 3 có giới thiệu một phương pháp
lập bảng số nguyên tố khác. Tôi xin trình bày lạiở đây:
Học sinh Sundaram người ấn Độ đã đưa ra phương pháp này năm 1934.
Trước tiên Sundaram liệt kê một bảng các số như sau:
4 7 10 13 16 19 22...
7 12 17 22 27 32 37...
10 17 24 31 38 45 52... (1)
13 22 31 40 48 58 67...
16 27 38 49 60 71 82...
.....................
Bảng số này có tính đối xứng (số ở hàng m cột n bằng số hàng n cột m)
Các số này được chọn bằng cách lần lượt thực hiện các bước sau đây:
1. Viết số 4 vào góc bên trái
2. Các số tiếp theo của hàng 1 lần lượt là số liền trước cộng thêm 3 (các sốtrên hàng 1 lập
thành cấp số cộng với công sai là 3)
3. Các số tiếp theo của hàng 2 lần lượt là số liền trước cộng thêm 5 (các sốtrên hàng 5 lập
thành cấp số cộng với công sai là 5)
.......
Dễ dàng tìm được công thức để tính giá trị số thứ m hàng thứ n:
S m,n = (2m+1)n + m = 2mn + m + n
Sundaram chỉ ra rằng: Nếu N có trong bảng (1) thì 2N+1 là hợp số. Nếu N không có trong
bảng (1) thì 2N+1 là số nguyên tố.
Để khẳng định điều đó, ta chứng minh mệnh đề tương đương sau: 2N+1 là hợpsố khi và
chỉ khi N thuộc bảng (1)
Chứng minh:
(2N+1=2(2mn+m+n)+1=(2m+1)(2n+1)
Do đó 2N+1 là hợp số
(=>) Nếu 2N+1 là hợp số, ta có: 2N+1=xy (x,y lẻ)
Đặt x=2m+1, y=2n+1
=> 2N+1=(2m+1)(2n+1)=2(2mn+m+n)+1
=> N=2mn+m+n
Suy ra N là số thứ m của hàng n trong bảng
Bây giờ ta thử xây dựng hai phương pháp trên thành chương trình.
Chương trình:
Vì Pascal không xây dựng được các mảng kích thước lớn (cỡ vài chục triệuphần tử), tôi
xin chọn VB 6.0 để thể hiện thuật toán.
Bạn tạo một Project và mở Module mới (lưu ý chọn Project Properties − Startup Object −
Sub Main()) để chạy chương trình.
Ta sử dụng mảng Mark() kiểu Byte để đánh dấu, lưu ý đối với mỗi phương phápmảng này
có ý nghĩa khác đôi chút:
- Sàng Eratosthenes: Mark(I)=0 nếu I là số nguyên tố, =1 nếu I là hợp số
- Phương pháp của Sundaram: Mark(I)=0 nếu 2*I+1 là số nguyên tố, =1 nếu 2*I+1 là hợp
số
Khai báo như sau:
Option Explicit
Dim Mark() As Byte
Dim N As Long
Trong đó biến N xác định cần tìm các số nguyên tố từ 2 đến N.
Sàng Eratosthenes
Đây là thủ tục thể hiện sàng Eratosthenes, vì đã qúa quen thuộc nên có lẽ không cần giải
thích nhiều với các bạn. Lưu ý một chút là ta chỉ cần xétcác số từ 2 đến sqrt(N):
Private Sub Eratosthenes()
'----------------------------------------------------------------------------------------------------------
' Thủ tục: Eratosthenes()
' Lập bảng số nguyên tố bằng sàng Eratosthenes
'----------------------------------------------------------------------------------------------------------
Dim I As Long
Dim K As Long
ReDim Mark(N) ′ định lại dung lượng cho mảng
Mark(0) = 1: Mark(1) = 1 ' 0 và 1 không phải số nguyên tố
' sử dụng sàng Eratosthenes
For I = 2 To Int(Sqr(N))
IfMark(I) = 0 Then ' nếu i là số nguyên tố
K= I * 2 ' gạch các bội số của i
Do While K >N/2 thì dừng lại
Xét hàng 2, tất nhiên xét từ ô (2,2) để bỏ qua giá trị trùng lặp, cho đến sốhạng > N/2 thì
dừng lại...
Cho đến hàng n mà giá trị của ô (n,n)>N/2 thì dừng lại.
ở mỗi số hạng K tìm thấy, ta đều đánh dấu Mark(K)=1 để chỉ 2*K+1 là hợp số
Toàn bộ qúa trình trên là để xác định trong phạm vi 2->N/2, số nào có trong bảng, số nào
không có trong bảng. Nhờ đó mà xác định được từ 2->N,số nào là số nguyên tố, số nào là
hợp số.
Thủ tục như sau:
Private Sub Sundaram()
'----------------------------------------------------------------------------------------------------------
' Thủ tục: Sundaram()
' Tạo bảng số nguyên tố bằng phương pháp của Sundaram
'----------------------------------------------------------------------------------------------------------
DimM As Long
DimK As Long
DimP As Long
' Lưu ý:Mark(0)=0 để chỉ 2 là số nguyên tố
ReDim Mark(N 2) ′ định lại dung lượng cho mảng
M = 0
Do M = M + 1
P = 2 * M + 1 ' các số trên hàng M lập thành cấp số cộng có công sai 2*M+1
K = M * (P +1) ' K là số nằm trên đường chéo của hàng M
Do While K> N/2 ' cho đến khi số trên đường chéo của hàng M+1 > N/2 thì dừng.
End Sub
Bạn có thểso sánh tốc độ hai thủ tục trên cùng một giá trị N như sau:
Dim t AsDouble
N = 10000000
So sánh giữa giá trị hiện ra trong hộp thông báo của đoạn mã:
t= Timer()
CallSundaram
MsgBoxTimer() − t
Và:
t= Timer()
CallErastosthenes
MsgBoxTimer() − t
Ngoài ra nếuthích bạn có thể trình bày bảng số nguyên tố ra file văn bản bằngthủ tục sau:
Private SubPrintPrimes(ByVal FileName As String, ByVal Kind As Boolean)
'----------------------------------------------------------------------------------------------------------
' Thủ tục:PrintPrimes
' In bảng sốnguyên tố đã tạo được ra text file
' Mô tả:FileName= tên File cần xuất
' Kind=Truenếu sử dụng sàng Eratosthenes,
' = False nếusử dụng sàng của Sundaram
'----------------------------------------------------------------------------------------------------------
DimI As Long
DimJ As Long
DimK As Long
DimP As Long
OpenFileName For Output As #1
' tiêu đề
Print#1, Space(20) & 'Bang cac so nguyen to tu 2 den ' & N
K = 6 ' viếtmột hàng 6 số
I = 0
Do
If Mark(I) =0 Then
IfKind Then ' sàng Eratosthenes
P= I ' Mark(I)=0 thì số nguyên tố cần viết là I
Else' sàng của Sundaram
P= IIf(I = 0, 2, 2 * I + 1) ' quy ước số nguyên tố cần viết = 2 nếuI=0,...
EndIf
IfK = 6 Then
Print#1, ' xuống dòng
K= 1
Else K = K + 1
EndIf
Print#1, Space(11 - Len(CStr(P))) + CStr(P); ' căn lề phải sao cho mỗi số đựơc12 kí tự
EndIf
I= I + 1
LoopUntil ((I > N/ 2) And (Not Kind)) Or (I > N) ' chỉ duyệt đến N/2 vớiphương pháp của
Sundaram
Close #1
End Sub
Ví dụ đểsử dụng thủ tục:
Sub Main()
N=10000000
CallSundaram
PrintPrimes(″D:Sundaram.txt″,False)
End Sub
Bạn nênxem file văn bản bằng font Courier New (nếu xem trên Windows), vì font nàycó
bề rộng các chữ bằng nhau (fixed-width font) nên các số sẽ đượcsắp thẳng cột
Tôi đã chạythử thủ tục Sundaram() với N=100 000 000- số nguyên tố lớn nhất tìmđược là
99 999 989, mất khoảng 88 giây (trên máy Celeron 700 Mhz, 128MB Ram, Windows 98 −
chương trình chạy trực tiếp, chưa biên dịch rafile.EXE), riêng file văn bản chiếm 60 MB
dung lượng. Trong khi đó thủtục Eratosthenes() mất tới 144 giây (thật không ngờ !!)
Có thểtrong các trường hợp trên, cách viết mã cũng như thuật toán chưađạt được hiệu qủa
cao nhất, dẫn đến việc so sánh không hợp lý. Vìthế rất mong nhận được sự góp ý của các
bạn, mọi trao đổi xin gửivề địa chỉ: Thân!