Hallo,
auf den ersten Blick kommen mir drei Vorschläge zur Optimierung der Performance deiner Codes:
1.) Du schreibst jede Primzahl einzeln in die Zellen. Das kostet sehr viel Zeit. Zellzugriffe (lesen und schreiben) sind allgemein zeitintensiv. Eine Möglichkeit, das zu verbessern ist die Verwendung eines Arrays. Damit kannst du in der Schleife die Primzahlen in das Array schreiben und dann am Ende das gesamte Array in das Tabellenblatt übergeben.
2.) Die Codes prüfen ob ein Primzahlkandidat durch jede Zahl (bzw. jede ungerade) Zahl teilbar ist. Man könnte auch die bereits gewonnenen Ereknntnisse (Primzahlen!) verwenden, und ausschließlich testen, ob ein Kandidat durch bereits ermittelte Primzahlen teilbar ist. Dadurch wird bei wird die Anzahl der Schleifendurchläufe der Inneren Schleife erheblich reduziert.
3.) Variablen richtig deklarieren. Das bringt auf meinem Rechner auch noch etwas Geschwindigkeit (wusste ich auch nicht).
Hier mein Vorschlag und mein Testsetting (ich empfehel eine neue Datei zu verwenden):
Sub code1()
Dim x1, x2, ti, i, max, pri
i = 1
ti = Timer
max = 1000000
For x1 = 2 To max
pri = True
For x2 = 2 To Sqr(x1)
If x1 Mod x2 = 0 Then
pri = False
Exit For
End If
Next x2
If pri Then
Cells(i, 1) = x1
i = i + 1
End If
Next x1
'MsgBox Timer - ti
End Sub
Sub code2()
Dim x1, x2, ti, i, max, pri
i = 2
ti = Timer
max = 1000000
Cells(1, 2) = 2
For x1 = 3 To max Step 2
pri = True
For x2 = 3 To Sqr(x1) + 1 Step 2
If x1 Mod x2 = 0 Then
pri = False
Exit For
End If
Next x2
If pri Then
Cells(i, 2) = x1
i = i + 1
End If
Next x1
'MsgBox Timer - ti
End Sub
Sub code1_arr()
'Variante von code1: es wird ein Array verwendet um den Zellzugriff zu reduzieren
Dim x1, x2, ti, i, max, pri
Dim ar(1 To 80000, 1 To 1)
i = 1
ti = Timer
max = 1000000
For x1 = 2 To max
pri = True
For x2 = 2 To Sqr(x1)
If x1 Mod x2 = 0 Then
pri = False
Exit For
End If
Next x2
If pri Then
ar(i, 1) = x1
i = i + 1
End If
Next x1
Cells(1, 3).Resize(UBound(ar), 1).Value = ar
End Sub
Sub code2_arr()
'Variante von code2: es wird ein Array verwendet um den Zellzugriff zu reduzieren
Dim x1, x2, ti, i, max, pri
Dim ar(1 To 80000, 1 To 1)
i = 2
ti = Timer
max = 1000000
ar(1, 1) = 2
For x1 = 3 To max Step 2
pri = True
For x2 = 3 To Sqr(x1) + 1 Step 2
If x1 Mod x2 = 0 Then
pri = False
Exit For
End If
Next x2
If pri Then
ar(i, 1) = x1
i = i + 1
End If
Next x1
Cells(1, 4).Resize(UBound(ar), 1).Value = ar
End Sub
Sub vorschlag()
Dim candidate As Long
Dim max As Long
Dim isPrime As Boolean
Dim i As Long, i2 As Long
Dim sqr_candidate As Double
Dim primes(1 To 80000, 1 To 1) As Long
max = 1000000
i = 1
primes(i, 1) = 2
primes(2, 1) = 3
For candidate = 3 To max Step 2
isPrime = True
i2 = 2
sqr_candidate = Sqr(candidate)
Do Until primes(i2, 1) > sqr_candidate
If candidate Mod primes(i2, 1) = 0 Then
isPrime = False
Exit Do
End If
i2 = i2 + 1
Loop
If isPrime Then
i = i + 1
primes(i, 1) = candidate
End If
Next candidate
Cells(1, 5).Resize(i, 1).Value = primes
End Sub
Sub test_them()
Dim i As Long, t
Const n = 2 'Anzahl der Makroaufrufe
'damit der gesamte code kompiliert ist
'und etwaigen overhead zu Beginn "nicht so erheblich mitmessen"
Call code1
Call code2
Call code1_arr
Call code2_arr
Call vorschlag
'eigentlicher Vergleich
t = Timer
For i = 1 To n
Call code1
Next
Debug.Print "code1: ", Timer - t
t = Timer
For i = 1 To n
Call code1_arr
Next
Debug.Print "code1_arr: ", Timer - t
t = Timer
For i = 1 To n
Call code2
Next
Debug.Print "code2: ", Timer - t
t = Timer
For i = 1 To n
Call code2_arr
Next
Debug.Print "code2_arr: ", Timer - t
t = Timer
For i = 1 To n
Call vorschlag
Next
Debug.Print "vorschlag: ", Timer - t
msgbox "fertig: siehe Direktfenster"
End Sub
code1 und code2 habe ich von dir übernommen. code1_arr und code2_arr nutzen ein Array und greifen so nur einmalig auf das Tabellenblatt zu.
"vorschlag" ist mein Vorschlag, in dem ich alle oben aufgeführten Ideen zu deinen Codes umgesetzt habe.
Das Makro "test_them" schreibt die gemessenen Zeiten in das Direktfenster der VBE.
Viele Grüße,
Ulrich
|