Die Primzahlfunktion pi(x) (Teil I: Berechnung) - T

Werbung
Karl Schwalen
Version 1.14
Weitere Aufsätze des Verfassers unter http://www.primath.homepage.t-online.de
Die Primzahlfunktion pi(x)
Kombinatorische und analytische Verfahren zur Berechnung von pi(x)
Die Primzahl(zähl)funktion π(x) bezeichnet die Anzahl der Primzahlen, die kleiner/gleich
einer vorgegebenen Zahl x ≥ 0 sind. Ist pi die i-te Primzahl gilt also π(pi) = i und
0 ≤ π(x) ≤ π(x+1). Der Wertebereich der Funktion (die nicht-negativen ganzen Zahlen) wird
sukzessive durchlaufen, wobei jeder Wert außer Null und Eins mindestens zweimal
hintereinander vorkommt (für ganze Zahlen x).
Die mittlere Dichte der Primzahlen nimmt mit zunehmender Größe von x immer mehr ab, da
die Anzahl der potentiellen Teiler zunimmt. Dem zufolge besitzt π(x) „global“ betrachtet
einen recht glatten Verlauf mit abnehmender Steigung (wie etwa Wurzel x oder ln(x) ). Das
bilden auch die Näherungen π(x) ≈ x / ((ln(x) – 1,08366) (Legendre) oder π(x) ≈ Li(x) (Gauß)
x
mit Li(x) =
∫ ln(1t ) dt ab, die durch Auszählen der zur damaligen Zeit vorhandenen (noch sehr
2
beschränkten) Primzahltabellen gefunden wurden.
Li(x) ist auch heute noch eine der besten Näherungen und für x →∞ sind π(x) und Li(x) sogar
asymptotisch gleich; d.h. die relative Differenz (π(x) – Li(x)) / π(x) geht gegen Null. (Das
bedeutet aber nicht, dass man eine feste Zahl N0 angeben könnte, so dass für beliebig große x
gelten würde: |π(x) – Li(x)| < N0.)
Schaut man sich den Verlauf von π(x) „aus der Nähe“ an, sieht man – beginnend mit π(1) = 0
– einen gestuften Verlauf, wobei die Stufen (Höhe 1), infolge der unregelmäßigen Lücken
zwischen benachbarten Primzahlen, unterschiedliche (für x > 3 geradzahlige) Abstände
aufweisen. Die Steigung der Funktion kann natürlich nicht negativ werden. Da nun keine
geschlossene Formel für die Primzahlfolge bekannt ist (und es wohl auch keine gibt), gilt das
auch für π(x) ; d.h. π(x) muss schlicht durch Zählen bestimmt oder aber berechnet werden.
Zu Letzterem werden in den Abschnitten I. und II. zwei vom Ansatz her völlig
unterschiedliche Verfahren behandelt.
Ein seit dem Altertum bekanntes Verfahren zur Bestimmung der Primzahlfolge ist das sog.
„Sieb des Eratosthenes“. Durch die Entwicklung der elektronischen Rechner hat dieses
Verfahren in der Praxis enorm an Leistungsfähigkeit gewonnen. Nach Angaben im Netz
beträgt derzeit (2013) die zur Bestimmung (und Zählen) der Primzahlen im Intervall [1, 109]
benötigte Zeit 0,02 Sek.(!). Geht man – wegen der mit zunehmendem x wachsenden Anzahl
erforderlicher Siebprimzahlen – davon aus, dass die Rechenzeit je Zehner-Potenz um den
Faktor 14 wächst, und die maximale „hinnehmbare“ Rechenzeit 6 Monate (ca. 15.768.000
Sek.) beträgt, lassen sich damit (in einem Durchlauf) alle Primzahlen und somit π(x) –Werte
bis rd. 6⋅1016 bestimmen.
Der bisher (2013) größte (mit einem kombinatorischen Verfahren; s.u.) bestimmte Wert ist
π(1023). Allerdings spielt auch bei diesen Verfahren das Sieb des E. – z.T. in leicht
abgewandelter Form – eine entscheidende Rolle, und wenn man z.B. unter Nutzung der im
Netz verfügbaren π(x) –Tabellen für einen nicht tabellierten x-Wert (z.B. x = 1017 +
1234567891) π(x) berechnen möchte, ist das Sieb des E. das Mittel der Wahl.
Eine einfache Version (für den „Hausgebrauch“) ist im Anhang I-A1 wiedergegeben.
1
I.
Die ‚kombinatorische’ Berechnung von π(x)
a) Die Grundlagen des Verfahrens
Die nachfolgenden Ausführungen stützen sich hauptsächlich auf die im Netz einsehbaren
Artikel von
[1] X. Gourdon: “Computation of pi(x): improvements to the Meissel, Lehmer, Lagarias,
Miller, Odlyzko, Deléglise and Rivat method“ und
[2] T. O. e Silva: “Computing π(x): the combinatorial method”.
Im Titel des erstgenannten Autors sind die Namen, mit denen die Entwicklung dieser
Methoden wesentlich verbunden ist, genannt.
Zunächst die Grundlagen der in Rede stehenden Verfahren in Kürze (wobei im folgenden p
immer eine Primzahl bezeichnet):
Φ (x, a) bezeichne die Anzahl der Zahlen ≤ x, die keinen Primteiler ≤ pa besitzen.
Φ (x, a) = |{ n≤
≤ x ; pmin(n) > pa }|
Φ k(x, a) bezeichne die Anzahl der Zahlen ≤ x, die genau k (nicht notwendigerweise
verschiedene) Primfaktoren besitzen, wobei keiner dieser Primfaktoren ≤ pa ist.
Φ k(x ,a) = |{ n ≤ x; pmin(n) > pa ; Ω(n) = k}|
Es ist dann (für x > 0):
Φ (x, a) = Φ 0(x, a) + Φ 1(x, a) +…+ Φ k(x, a) +.. mit Φ 0(x, a) = 1 und Φ 1(x, a) = π(x) – a
Klarerweise ist Φk(x, a) gleich Null, wenn x < p ak+1 ist, was gleichbedeutend ist mit
a + 1 ≥ π( x 1 / k ) . Damit ist Φk(x, a) nur dann größer Null, wenn k ≤ ln(x) / ln(pa + 1) .
Löst man nach π(x) auf, erhält man die für diese Verfahren fundamentale Gleichung

π(x) = Φ(x, a) + a – 1 –
ln ( x )
ln ( p a + 1 )

∑ Φ k ( x , a)
k =2
Der wahlfreie Parameter a bietet nun die erste Möglichkeit zur Optimierung des Verfahrens.
Er wird meist – wie auch hier – so festgelegt, dass kmax = 2; d.h. a = π(x t) mit 1/3 ≤ t ≤ 1/2.
Damit hat man als Bestimmungsgleichung: π(x) = Φ (x, a) + a – 1 – Φ 2(x, a). (∗)
Vorbemerkung: Bei der kombinatorischen Berechnung von π(x) spielen nur ganze Zahlen
eine Rolle.
Zur Vereinfachung der Schreibweise werden daher hier die Rundungszeichen xy
generell weggelassen; z.B. wird a / b als a \ b geschrieben (Ganzzahldivision) und y(c/g)
versteht sich als  y(c/g) .
Die entscheidende Größe zur Bestimmung von π(x) gemäß (∗) ist Φ(x, a).
Daher sollen die Eigenschaften und Verfahren zur Bestimmung von Φ(y, c) zunächst etwas
eingehender betrachtet werden.
2
b) Das partielle Sieb Φ(y, c)
Bei bekanntem π(y) kann (*) natürlich auch zur Bestimmung von Φ(y, c) genutzt werden.
Es gilt in den nachstehend definierten
Bereichen:
(α)
(β)
1≤y<
pc ≤ y <
pc + 1 bzw. π(y) < c + 1
→ Φ(y, c) = 1
1/2
2
pc +1 bzw. π(y ) < c + 1 ≤ π(y) + 1 → Φ(y, c) = π(y) – c + 1
(γ) pc2+1 ≤ y < p3c +1 bzw. π(y1/3) < c + 1 ≤ π(y1/2)
→ Φ(y, c) = π(y) – c + 1 + Φ2(y, c)
Die letzte Gleichung ist auch für y < pc2+1 gültig, aber dann ist – wie oben gesagt – Φ2(y, c)
gleich Null.
Periodizität:
Φ(y, c) ist periodisch mit der Periode 2⋅3⋅....⋅pc (= Πpc). In jeder Periode gibt es genau
Π(pc – 1) Zahlen n mit pmin(n) > pc. Ist y > Πpc , ermöglicht das die vereinfachte Berechnung
mittels der Formel
Φ (y, c) = Π(pc – 1) ⋅ (y \ Πpc) + Φ (y mod Πpc, c). (∗∗)
y mod Πpc kann dabei die Werte von 0 bis Πpc – 1 annehmen. Zweckmäßigerweise wird man
für diese Werte Φ(y mod Πpc, c) vorberechnen und in einer Tabelle abspeichern.
Inklusion / Exklusion:
Φ(y, 0) = y, Φ(y, 1) = y – y \ 2, Φ(y, 2) = y – y \ 2 – y \ 3 + y \ 6 , usw.
y
Allgemein : Φ(y, c) =
∑ µ ( n ) ⋅y \ n
mit pmax(n) ≤ pc. Es sind also alle Zahlen kleiner als y
n =1
auszusieben, die einen Primteiler größer als pc besitzen sowie die nicht-quadratfreien Zahlen
(µ(n) = 0). Die Formulierung Φ(y, c) =
∑ µ(ny) ⋅n
zeigt, wie die Bestimmung der n-Werte
n | Πp c
einigermaßen effizient durchgeführt werden kann: Zunächst teilt man c in zwei etwa gleiche
Teile auf: c1 = c \ 2; c2 = c – c1. Nun sind sukzessive alle Teiler µ(n) ⋅n von 2⋅3⋅5⋅..⋅pc1 zu
berechnen, z.B. indem man alle zuvor berechneten (und gespeicherten) Teiler mit dem
negativen Wert des nächstgrößeren Primteiler multipliziert: 1; –2⋅1; –3⋅1, (–3)⋅(–2); –5⋅1,....
Die auf diese Weise berechneten, mit µ(n) multiplizierten 2c1 Teiler von 2⋅3⋅5⋅..pc1 sind
abschließend noch nach ihrem aufsteigenden Absolutbetrag zu sortieren. Die Teiler, deren
Betrag größer als y ist, können natürlich weggelassen werden.
Analog werden alle in Frage kommenden Teiler von pc1+1⋅...⋅pc gefunden und gespeichert.
Jede Zahl der ersten Teilermenge ist nun mit jeder Zahl der anderen Teilermenge zu
multiplizieren. Aufgrund der Sortierung nach Größe kann jeweils zum nächsten Teiler der
ersten Teilermenge übergegangen werden, sobald das Produkt größer als y ist. Dadurch
brauchen – in Abhängigkeit von y – z.T. mehr als 95% der 2c Teiler erst gar nicht
ausgerechnet zu werden.
Auf diese Weise kann in ‚erträglicher Zeit’ z.B. Φ(1021, 55) berechnet werden. Bei
Anwendung von (∗) beträgt der kleinste Wert von a für x = 1021 aber 664.579 (= π(1021/3)).
Daraus ist ersichtlich, dass die Berechnung andere Verfahren erfordert.
3
Aussieben und Aufsummieren:
Analog zum Sieb des Eratosthenes werden in einem Vektor d() der Länge y0 ≤ y sukzessiv
alle Vielfachen der Primzahlen pi ≤ pc markiert (einschließlich der pi selbst). Sind die
verbleibenden Zahlen durch „1“ gekennzeichnet (die übrigen mit „Null“), erhält man Φ(y0, c)
y0
durch Zählen der Einsen; also Φ(y0, c) =
∑ d(i) . Sowohl beim Sieben als auch beim
i =1
Aufsummieren brauchen (für c > 0) ersichtlich nur die ungeraden i berücksichtigt zu werden.
Ist y > y0, ist der vorstehend beschriebene Prozess für das Intervall ]y0 , y] zu wiederholen;
Φ(y, c) ergibt sich dann aus
y
Φ(y, c) = Φ(y0, c) +
∑ d(i) . Entsprechendes gilt natürlich auch, wenn aufgrund der Größe
i = y 0 +1
von y und/oder y0 (verfügbarer Arbeitsspeicher) y \ y0 > 2 ist („segmentiertes Sieb“).
Rekursion:
Wie oben erwähnt, ist
Das ist darstellbar als
Φ(y, 2) = y – y \ 2 – y \ 3 + y \ 6
Φ(y, 2) = Φ(y,0) – Φ(y\2,0) – Φ(y\3,0) + Φ(y\6,0)
Zusammenfassen :
Φ(y ,2) =
Φ(y,1)
Φ(y\3,1)
–
Das lässt sich verallgemeinern zu Φ (y, c) = Φ (y, c–1) – Φ (y \ pc, c–1)
Φ(y, c) kann also als binärer Baum dargestellt werden, wobei die Summe der ‚Knoten-Werte’
jeder Ebene gleich Φ(y, c) ist. (Die obige Inklusion/Exklusions-Formel gibt, wie im Beispiel
gezeigt die Summe der Ebene 0 dieses Baumes wieder.)
Eine bemerkenswerte Folgerung aus der Rekursions-Formel ist: Die Anzahl der Zahlen ≤ y,
deren kleinster Primteiler pc ist, ist gleich der Anzahl der Zahlen ≤ y \ pc, deren kleinster
Primteiler ≥ pc ist. In Zeichen: |{n ≤ y; pmin(n) = pc}| = |{k ≤ y \ pc ; pmin(k) ≥ pc}|
c −1
Die wiederholte Anwendung ergibt: Φ(y, c) = Φ(y, r) –
∑ Φ ( py
i=r
i +1
, i ) mit 0 ≤ r ≤ c.
Im Ergebnis bewirkt diese Umformung für alle i > r eine zunehmende Verkleinerung der
benötigten Sieblänge. Die Fortentwicklung dieses Ansatzes führt zu dem im Folgenden
dargestellten Verfahren.
4
c) Die Berechnung von Φ(x, a) (das kombinatorische Verfahren)
Hinsichtlich der detaillierten Herleitung des beschriebenen Verfahren wird auf [1] und [2]
sowie auf die dort zitierten Artikel verwiesen, wobei in der algorithmischen Umsetzung hier
im Einzelnen „eigene Wege“ beschritten werden. Im Anhang I-A2 ist das komplette
Programm wiedergegeben, welches im Folgenden in den wesentlichen Teilen erläutert wird.
Die Berechnung von Φ(x, a) mit a = π(aa) und aa = xt ; 1/3 < t < 1/2 wird zunächst unterteilt
in
Φ (x, a) = S0 + S
aa
•
Es ist
S0 =
∑ µ(n)⋅Φ ( xn , v )
0
mit pmin(n) > pv0 und v0 ≥ 0
n =1
Kennzeichen von S0 ist, dass alle Werte, für die Φ zu berechnen ist, größer als x \ aa sind; das
ist eine wichtige Kenngröße des Verfahrens, die im Weiteren mit ‚rr’ bezeichnet wird. Wie
unter b) gesagt, ist die schnelle Berechnung von Φ für großes x \ n nur für kleine v0 möglich.
v0 ist daher so festzulegen, dass (∗∗) angewendet werden kann.
Besonders einfach ist natürlich die Wahl v0 = 0:
aa
S0 (v0 = 0) =
∑ µ(nx)⋅n wobei die n-Werte alle quadratfreien Zahlen ≤ aa durchlaufen.
n =1
Die Bestimmung der Werte von n und µ(n) kann für beliebiges v0 in einem einzigen,
nachfolgend mit f( ) bezeichneten Sieb-Vektor der Länge aa erfolgen. Dabei werden zunächst
alle µ(n)-Werte eingetragen. Verfügt man über eine (vorausberechnete) Tabelle p( ) aller
Primzahlen ≤ aa (was im Weiteren – ebenso wie eine bis mindestens x1/2 reichende π(y)Tabelle pi( ) – immer als 1. Schritt einer π(x)-Berechnung angenommen wird) geht das
besonders einfach:
For i = 1
For i = 1
For
Next i
For i = 1
For
Next i
For i = 2
For
Next i
to aa: f(i) = 1: Next i
to π(aa^(1/2))
j = p(i)^2 to aa Step p(i)^2: f(j) = 0: Next j
((Damit sind alle nicht-quadratfreien Zahlen mit ‘0’ markiert.))
to π(aa)
((= a))
j = p(i) to aa Step p(i): f(j) = – f(j): Next j
((Nun liegt µ(n) für n ≤ aa in f( ) vor; es folgt
to v0
das Aussieben der n mit pi | n und pi ≤ pv0.))
j = p(i) to aa Step 2⋅p(i): f(j) = 0: Next j
((Außer für v0 = 0 spielen im f()-Sieb nur ungerade Zahlen eine Rolle.))
f(m) ist also nur für die m ≠ 0, die keinen Teiler ≤ pv0 haben und quadratfrei sind. Für diese
m ist f(m) = µ(m). Im weiteren Verlauf der Rechnung wird pv sukzessiv erhöht.
S0 kann nun mit Hilfe von (∗∗) schnell berechnet werden.
Anmerkung:
Um die nachfolgende Darstellung einigermaßen übersichtlich zu halten,
– wird die bei großen x-Werten erforderliche Sieb-Segmentierung nicht behandelt.
Wenn die Programmierplattform 4 GB Arbeitsspeicher verwalten kann, ist auch ohne
Segmentierung eine π(x)-Berechnung bis etwa 1018 möglich. (Bei der vorliegend
benutzten Plattform können etwa 3 GB mit Arrays belegt werden.)
– werden nachfolgend einige sonst erforderliche Fallunterscheidungen nicht
berücksichtigt, so dass das Programm nur für aa ≥ x0,4 (also t ≥ 0,4) korrekt ist, (was
aber keine wirkliche Einschränkung darstellt, da das Optimum für die hier
beschriebene Vorgehensweise bei t > 0,47 liegt.)
5
a −1
aa
∑ ∑ µ(m)⋅Φ( mx⋅p , v −1)
Es ist S = –
mit u = aa , pmin(m) > pv (und
pv
v
v = v 0 +1 m = u +1
x < x = rr)
aa
m⋅ p v
Diese Formel wird nachstehend nicht direkt verwendet, sondern die erste SummationsSchleife (v = v0 + 1 bis a – 1) wird in 4 Bereiche unterteilt und zwar in
v0 + 1 bis π(x1/5) (= v1)
v1 + 1 bis π(aa1/2) (= v2)
v2 + 1 bis π(x1/4) (= v3)
v3 + 1 bis a – 1
Mit diesen Abgrenzungen gilt also S = S1 + S2 + S3 + S4
v1
•
aa
∑ ∑
S1 = –
µ( m )⋅Φ ( x , v −1)
v = v 0 +1 m = paav +1
m⋅ p v
Die m-Werte mit µ(m) ≠ 0 der inneren Summe erhält man aus der Weiterführung des oben
eingeführten Siebes f() – also je v der äußeren Summe durch die Setzung f(i) = 0 für p(v)| i .
Bei Beginn mit m = aa, bilden die Zahlen x \ m⋅pv eine monoton ansteigende Folge, so dass
alle Φ-Werte je v in einem einzigen Durchlauf des Siebvektors d() gewonnen und
aufsummiert werden können.
Verkompliziert wird das sehr einfache Verfahren ein wenig, damit beide Schleifen mit
‚Schrittweite 2’ durchlaufen werden können (die Startwerte ao und ru müssen jeweils
ungerade sein, was für gerades y wegen Φ(y, c) = Φ(y – 1, c) immer möglich ist), und weil es
durchaus vorkommen kann, dass zwei aufeinanderfolgende Werte x \ (m⋅pv) gleich sind bzw.
Differenz 1 haben.
s1 = 0
ao = aa: If ao mod 2 = 0 Then ao = ao–1
For v = v0+1 to v1
ps = p(v–1): d(ps) = 0: iu = ps^2 ((In d() mit pv-1 sieben))
For i = iu to rr Step 2*ps: d(i) = 0: Next i
pv = p(v): f(pv) = 0: pq = pv^2
((In f() mit pv sieben))
For i = pq to aa Step 2*pv: f(i) = 0: Next i
mv = aa\pv + 1: xp = x\pv
If xp\ao > pq Then ru = pq: h = pi(pq)–v+2 Else ru = pv+2: h = 2
For m = ao to mv Step –2
If f(m) = 0 Then Iterate
rz = xp\m
If rz < ru Then s1 = s1–f(m)* h: Iterate
For j = ru to rz Step 2: h = h+d(j): Next j
s1 = s1–f(m)* h: ru = rz+1: If ru mod 2 = 0 Then ru = ru+1
Next m
Next v
v2
•
S2 =
∑
v = v 1 +1
π(
π( x / p 3v )
∑
i = π( aa / p v )
π( x ) − v + 2 +
p i ⋅p v
x
p i ⋅p v
∑ ( π( p ⋅px ⋅p ) − j + 1)
j= v
aa
∑
+
m = x / p 3v +1
)
j
i
+
v
− µ( m) ⋅  π( x ) − v + 2 
 m⋅ p v

Hier wird – anstelle die Φ-Werte durch Auswerten des d()-Siebes zu bestimmen – von der
π(x)-Tabelle Gebrauch gemacht. Für v > v1 (= π(x1/5) – also pv ≤ x1/5 < pv + 1 – sind im
Bereich aa \ pv bis x \ pv3 (= x2/5) die m-Werte ausschließlich Primzahlen (µ(m) = – 1), so
6
dass das f()-Sieb nicht benötigt wird. Wie man durch Einsetzen der Summationsgrenzen sieht,
ist des weiteren in diesem Bereich x1– t < x \ (pi⋅pv) < x2/5 und somit x \ (pi⋅pv) < pv3 (= x3/5)
jedenfalls erfüllt, so dass Φ(y, v) = π(y) – v + 1 + Φ2(y, v), (s. γ in Ziffer b) gilt, was der
Inhalt der ‘runden’ Klammer ist.
Im Bereich x \ pv3 +1 bis aa müssen die m-Werte dagegen durch das f()-Sieb bestimmt
werden; in diesem Bereich ist Φ(y, v) = π(y) – v + 1.
Reicht die π(y)-Tabelle nicht bis y = rr, sind die Werte x \ (pi⋅pv) > y in einer gesonderten
Tabelle zu sammeln und die betr. Φ-Werte können später ermittelt und S2 zugeschlagen
werden (siehe am Schluss des Programm in Anhang I-A2).
Insgesamt kann S2 auf diese Weise deutlich schneller berechnet werden, als bei Anwendung
des für S1 (notwendigerweise) gewählten Verfahrens.
v3
•
∑
S3 =
π(
π( x / p 3v )
∑
π( x ) − v + 2 +
p i ⋅p v
v = v 2 +1 i = v + 1
x
p i ⋅p v
)
∑ ( π( p ⋅px ⋅p ) − j + 1)
j
j= v
a
∑
+
i = π( x / p 3v ) +1
i
+
v
 π( x ) − v + 2 
 p i ⋅p v

Gegenüber S2 sind nur zwei Änderungen zu vermerken:
– Da f() bereits mit allen Primzahlen < aa1/2 gesiebt wurde, enthält f() nur noch
Primzahlen und ist somit überflüssig.
– Die Summenbildung im ersten Summanden (hinter der geschweiften Klammer)
beginnt – anstelle bei π(aa \ pv) – bei v + 1.
a −1
a
∑ ∑ Φ( p x⋅p , v −1) ist nach [1] Summe der folgenden, leicht und schnell
• S4 =
i
v = v 3 +1 i = v +1
v
zu berechnenden Terme, wobei b = π(x1/3) und c = π((x \ aa)1/2) ist:
(a – b)⋅(a – b – 1) \ 2 + a⋅[b – c – c⋅(c – 3) \ 2 + v3⋅(v3 – 3) \ 2] +
+ v3 – v3⋅(v3 – 1)⋅(2v3 – 1) \ 6 – b + b⋅(b – 1)⋅(2b – 1) \ 6 +
c
∑
+ a⋅
π( x )
p i ⋅ aa
i = v 3 +1
b
+
b
b
+
∑
i = c +1
π( x2 )
pi
–
∑
i = v 3 +1
2
 π( x )  +

p i 

π(( pxi )1 / 2 )
∑ ∑ f ⋅ π( p x⋅ p ) mit f = 1 falls x \ (p ⋅p ) ≥ aa; sonst f = 2
i
i = v 3 +1 j= i +1
i
j
j
Alle benötigten π(xy)-Werte sind kleiner als π(x1/2) und können somit der
vorberechneten pi()-Tabelle entnommen werden.
Damit ist die Berechnung von Φ(x, a) = S0 + S1 + S2 + S3 + S4 abgeschlossen.
7
d) Die Berechnung von Φ2(x, a)
Gemäß Definition gilt pi⋅pj ≤ x mit i, j > a. Im Weiteren sei e = π(x1/2). i durchläuft den
Bereich a +1 ≤ i ≤ e, so dass a + 1 ≤ j ≤ π( x ) und somit
pi
e
Φ2(x, a) =
π( )
x
pi
∑ ∑
1=
i = a +1 j= i
e
∑
i = a +1
 π( x ) − i + 1 = a ⋅( a − 1) − e⋅( e − 1) +
2
2
 pi

e
∑ π( px )
i = a +1
i
Da die benötigten pi oberhalb der vorberechneten Primzahltabelle liegen und die Werte von
x \ pi zwar alle kleiner als rr sind, aber u.U. über die π(y)-Tabelle hinausgehen, benutzt man
zweckmäßigerweise das nach Abschluss der Berechnung von S1 nicht mehr benötigte Φ-Sieb
d(), aus dem die Primfaktoren < v1 bereits entfernt sind, weiter. Nachdem d() mit den
Primzahlen kleiner π(rr1/2) gesiebt wurde, enthält d() im Intervall [aa, rr] ausschließlich
Primzahlen, so dass sowohl die pi zur Verfügung stehen, als auch die π( x ) jeweils
pi
ausgezählt werden können. Dabei ist bei x mit dem Wert e = π(x ) zu beginnen. Wegen der
‚Schrittweite 2’ müssen die Startwerte jeweils ungerade sein.
1/2
1/2
For i = v1+1 to pi(rr^(1/2))
For j = p(i)^2 to rr Step 2*p(i): d(j) = 0: Next j
Next i
phi2 = 0: ee = x^(1/2): e = pi(ee): h = e
u = ee+1: If u mod 2 = 0 Then u = u+1
m = ee:
If m mod 2 = 0 Then m = m–1
For i = m to aa + 1 Step –2
If d(i) = 0 Then Iterate
xi = x\i
For j = u to xi Step 2: h = h+d(j): Next j
phi2 = phi2 + h
u = xi+1: If u mod 2 = 0 Then u = u+1
Next i
phi2 = phi2 + a*(a–1)\2 – e*(e–1)\2
Anmerkungen:
x 1/ 2
π( x 1 / 3 ) π(( pi ) )
1. Φ3(x, a) =
∑ ∑
i = a +1
j= i
 π( x ) − j + 1
 p ⋅p

i
j


2. Für jedes gerade y > 2 gilt π(y) = π(y – 1). Daher reicht es, die π(y)-Datei für
ungerade y zu speichern. Dadurch kann der Speicherplatzbedarf halbiert bzw.
die Reichweite verdoppelt werden. Allerdings erfordert dann jeder Aufruf der
Datei eine Ganzzahldivision durch 2. Dadurch würde sich bei dem
vorliegenden Programm infolge der häufigen Zugriffe die Rechenzeit um mehr
als 11% erhöhen, weswegen darauf verzichtet wurde.
Ähnliches trifft für die Vektoren f() und d() zu; vor allem würde das Programm
unübersichtlicher.
3. Hinweis zur Ganzzahldivision „div“ oder „\“:
Es gilt (wie bei der normalen Division): a div (b⋅c) = (a div b) div c
Bei variablem c kann damit die mehrfache Berechnung von b⋅c vermieden
werden.
8
e) Ergebnisse, Auswertung
Mit dem im Anhang I-A2 aufgeschriebenen, auf der Programmierplattform PB Console
Compiler 6.02 lauffähigen Programm, einer 2,4 GHz–CPU und a = π(x0,4725) erhält man die
folgenden Laufzeiten:
N
Rechenzeit (Sek.)
1012
0,41
13
10
1,8
1014
8,3
15
10
39,4
1016
189,2
1017
926,6
Je Zehner-Potenz nimmt die Rechenzeit etwa um den Faktor 4,8 zu.
Leider wurden im Netz keine (aktuellen) Referenzwerte zur Beurteilung dieser Werte
gefunden. Angeblich betrug die Dauer der Berechnung von π(1023) ca. 2 Monate. Rechnet
man das mit dem Faktor 4,8 6 auf 1017 zurück, ergibt das rd. 440 Sek. für 1017 – also etwas
weniger als die Hälfte der o.a. genannten Zeit. Die Zeit-Differenz könnte evtl. zu je einem
Drittel einem leistungsfähigeren Rechner, einer schnelleren Plattform (mit maschinennaher
Programmierung) und einem effizienteren Algorithmus zugeordnet werden.
Beim Programm gemäß I-A2 entfallen über 85 % der Rechenzeit auf die Berechnung von S1
und S2. Eine Verbesserung müsste also vor allem an dieser Stelle ansetzen (siehe [2]).
Das dargestellte Verfahren lässt sich offensichtlich sehr leicht in Einzelsegmente zerlegen, die
parallel auf mehreren PC berechnet werden können, da jeder v-Wert (abgesehen vom Sieben
des d()-Vektors) separat abgearbeitet werden kann. Dennoch ist bislang die Berechnung von
π(1024) nicht gelungen. Insgesamt scheint die Leistungsfähigkeit des Verfahrens bei
Verwendung eines PC allenfalls bis x = 1025 zu reichen.
Fazit: Aufgrund der Leistungssteigerung der PC ist mit dem beschriebenen Verfahren
inzwischen auch dem Nichtspezialisten der Zahlbereich bis 1018 für Untersuchungen, die die
Kenntnis von π(x) erfordern, zugänglich – auch wenn es jenseits von 1016 noch etwas
’langwierig’ ist.
Das Programm in I-A2 besteht im Wesentlichen aus einfachsten Befehlen/Anweisungen. Zu
erläutern sind allenfalls:
ITERATE : Überspringt (bei Erfüllung einer vorgegebenen Bedingung) den zwischen
ITERATE und dem Ende der aktuellen Schleife (NEXT, LOOP) liegenden
Programmteil.
REDIM a(u TO o): Dimensioniert den Vektor a() auf die gewünschte Länge o – u.
ARRAY SORT a() FOR k : Sortiert die ersten k Einträge im Vektor a() nach Größe
aufsteigend.
9
II. Die „analytische“ Methode zur Berechnung von π(x)
a) Die explizite Formel von Riemann
Ausgangspunkt ist die Funktion J(x)
∞
∑
1
=
m
pm ≤ x
=
∑ 1n π (x
1
n
) . (x keine Primzahlpotenz)
n =1
J(x) zählt also gewissermaßen die Primzahlpotenzen < x. B. Riemann erkannte und H. von
Mangoldt bewies, dass
∞
J(x) = li(x) –
∑{li(x
ρk
) + li( x
ρk
∞
)} – ln(2) +
k =1
∫ t(t
2
1
dt
−1)⋅ln( t )
(∗)
x
ρ = σ + j⋅t bezeichnet die nicht-trivialen (t > 0) Nullstellen der komplexen ζ-Funktion und
ρ = σ – j⋅t die (stets existierende) zu ρ konjugierte Nullstelle.
Abspalten von π(x) in der Definitionsgleichung für J(x)) – also J(x) = π(x) +
∞
∑ 1n π (x
1
n
)
n=2
und Einsetzen in (∗) ergibt – unter Verwendung einer (üblichen) vereinfachten Schreibweise
für den Nullstellenterm:
π(x) = li(x) – ∑ li ( x
ρk
∞
) – ln(2) +
ρk
∫
∞
1
dt
t ( t 2 −1)⋅ln ( t )
x
–
∑ 1n π (x
1
n
)
(∗∗)
n=2
Riemann löste (∗) vermittels der Möbius Inversion nach π(x) auf, so dass auf der rechten Seite
alle π(x)-Terme verschwinden:


∞
∞

ρk
1
µ( n ) 
1
n
n
π(x) =
li ( x ) −
li( x ) − ln (2) +
dt  (∗∗∗)

2
n
t ( t − 1)⋅ln ( t )


1
n =1
ρk
n
x


Da sich im deutschsprachigen Netz nur wenige Beiträge zur konkreten Anwendung dieser
„analytischen“ Formeln zur Berechnung von π(x) finden, soll das im Weiteren etwas
ausführlicher behandelt werden.
∑
•
∑
∫
Zunächst ist festzustellen, dass in den Formeln alle Summen (mit Ausnahme derjenigen
1
über die Nullstellen) nur über endlich viele Summanden zu bilden sind: Für x n < 2 ist
1
π( x n ) = 0; somit ist in (∗∗) und (∗∗∗) der höchste Summationsindex o = ln x / ln 2 .
falls n = 1
1
•
Def. der Möbius-Funktion: µ(n) =
( −1) falls n quadratfrei; mit r verschied. Pr imteilern
r
0
sonst
∞
•
Das Integral I(x) =
∫ t(t
2
1
dt :
−1)⋅ln( t )
I(2) ≈ 0, 1402... ; für 2 < x < 10 kann es durch
x
0,45⋅x
I(x) ≈ arctan(
ln ( x )
)/x 2,7 gut angenähert werden; I(10) = 0,0018..; I(x) ≈ 0 für x > 10.
10
•
Die Anwendung von Formel (∗∗∗) (anstelle von (∗∗) ) dürfte nur infrage kommen, wenn
1
die Bestimmung der Werte von π( x n ) (n > 1) aufwendig ist – also für große x. Dann
spielen die beiden Terme ln(2) = 0,693147.. und I(x) (insbesondere wegen des
wechselnden Vorzeichen von µ(n) und in Hinblick darauf, dass man ohnehin nur T (< ∝)
Nullstellen berücksichtigen kann) keine Rolle mehr, so dass man schreiben kann
π(x) ≈ π (x) =
*
o
∑
n =1
1
µ( n )
li( x n )
n
o
–
∑
n =1
µ( n )
n
T
∑
li( x
ρk
n
)
k =1
Der erste der beiden Terme wird in Würdigung der Verdienste von B. Riemann um dieses
Thema mit Ri(x) bezeichnet.
x
•
Zur Berechnung von li(x) =
∫ ln1( t ) dt („Logarithmus-Integral“, wegen des Pols bei t = 1
0
als Cauchy’scher Hauptwert zu verstehen) macht man von der Reihenentwicklung
li (x) = γ + ln(ln(x)) +
∞
∑
k =1
( ln ( x )) k
k⋅k!
Gebrauch. γ = 0,5772156649... (Euler-Konstante)
Es gilt li(x) = Ei(ln(x)) („Exponential-Integral“).
Zur Vermeidung zu großer Zahlen bei der Rechnung (etwa k⋅k!) benutzt man
zweckmäßigerweise die Rekursion
(ln( x )) k
k ⋅k !
=
(ln( x )) k −1 ln( x )⋅( k −1)
⋅
( k −1)⋅( k −1) !
k2
.
Nachstehender Programm-Code berechnet li(x) auf der aus dem Netz frei
herunterladbaren Plattform „ari.bas“ von Prof. O. Forster, München. (Diese ist für solche
Berechnungen gut geeignet, da Ganzzahlen mit bis zu ca. 3000 Stellen exakt dargestellt
werden und bei Gleitkommazahlen die Genauigkeit zwischen 32 und ca. 4000 Stellen
eingestellt werden kann.)
Nach Vorgabe von ’nn’ wird li(x) für 2 ≤ x = 2n ≤ 2nn berechnet.
function rr(nn: integer);
var
n,k: integer;
r,s,t,t1,u,g,w,x,li: real;
begin
u:= 10**(-12); g:=0.5772156649015328;
for n:=1 to nn do
x:=2**n;
w:=log(x); s:=w; r:=w;
for k:=2 to 10000 do
t1:=w*(k-1); t:=t1/k**2;
r:=r*t;
s:=s+r;
if r<u then break; end;
end;
li:=g+log(w)+s;
writeln(n," li(x): ",li:25:5,"
",k);
end;
end.
•
Die vorstehend für li(x) angegebene Entwicklung ist auch gültig, wenn x eine komplexe
Zahl z ist (hier: z = xρ). Die konkreten Rechnungen scheitern allerdings, da das
Konvergenzverhalten schlecht ist und die benötigte Rechenpräzision nicht einzuhalten ist.
Einen guten Ausweg bietet die asymptotische Entwicklung des Exponential-Integral zu
11
z
Ei(z) ≈ e
z
c
∑ zk! . Allerdings ist zu beachten ist, dass die Entwicklung ab einem
k
k =0
bestimmten Glied divergiert ( Wahl von c). Unter Beachtung dieser Einschränkung hat
man also
ρ
ρ
Ei(ln(x )) = li(x ) ≈
xρ
ln( x ρ )
c
∑ (ln(kx ! ))
ρ
k
k =0
=
6
xρ (1 + 1 +
2
+
ln( x ρ )
ln( x ρ ) (ln( x ρ )) 2 (ln( x ρ )) 3
+ ..)
Überlässt man die Berechnung von li(xρ) nicht einem Computer-Algebra-System sind die
in der Entwicklung auftretenden Größen nach den bekannten Regeln der komplexen
Rechnung nach Real- und Imaginär-Teil getrennt auszurechnen:
Mit ρ = σ + j⋅t ist xρ = xσ⋅ej⋅t⋅ln x = xσ⋅(cos(t⋅ln x) + j⋅sin(t⋅ln x)) ; ln(xρ) = |σ⋅ln x| + j⋅t⋅ln x.
Das ergibt:
σ
x ρ = x ⋅{cos ( t ⋅ln x ) ⋅ σ⋅ln x + sin ( t ⋅ln x ) ⋅ t ⋅ln x }
ln( x ρ )
( σ⋅ln x ) 2 + ( t ⋅ln x ) 2
=
x σ ⋅{cos ( t ⋅ln x ) ⋅ σ + sin ( t ⋅ln x ) ⋅ t}
+j
+j
ln x⋅ ( σ 2 + t 2 )
x σ ⋅{sin ( t ⋅ln x ) ⋅ σ⋅ln x − cos ( t ⋅ln x ) ⋅ t ⋅ln x }
( σ⋅ln x ) 2 + ( t ⋅ln x ) 2
x σ ⋅{sin ( t ⋅ln x ) ⋅ σ − cos ( t ⋅ln x ) ⋅ t }
ln x⋅ ( σ 2 + t 2 )
Unter Berücksichtigung dass arctan(-y) = – arctan(y), sin(-x) = – sin(x) , cos(-x) = cos(x)
und mit Hilfe des Satzes von DeMoivre folgt für k > 0:
k!
( ln ( x ρ )) k
=
k !⋅cos ( k⋅arctan ( t σ ))
{( σ⋅ln x ) 2 + ( t ⋅ln x ) 2 }k / 2
–j
k !⋅sin ( k⋅arctan ( t σ ))
{( σ⋅ln x ) 2 + ( t ⋅ln x ) 2 }k / 2
(Rekursive Berechnung geht
natürlich auch; siehe Programm-Beispiel unten.)
Da der Wert der konjugierten Nullstelle ρ auf den gleichen Realteil führt und der
Imaginärteil sich ebenfalls nur im Vorzeichen unterscheidet, stellt der verdoppelte
Realteil das (reelle) Ergebnis für diese beiden Nullstellen dar.
•
Bei allen bisher berechneten nicht-trivialen Nullstellen der Zeta-Funktion ist σ = ½ (und
Riemann vermutete, dass nur solche existieren. Bewiesen ist, dass alle Nullstellen im
Streifen 0 < σ < 1 liegen und für mehr als 40% der Nullstellen σ = ½ ist. Bezüglich der
Nullstellen-Anzahl, für die t < T gilt, ist N(T) ≈ T (ln( T ) − 1) ).
2⋅ π
2⋅π
Die (aufwendige) Berechnung der imaginären Anteile t erübrigt sich, da diese im Netz zur
Verfügung stehen. Vorliegend wurde eine (problemlos auswertbare) Textdatei von
A. Odlyzko benutzt (rd. 2 Mio mit 9 Nachkommastellen berechnete t-Werte; rd. 35 MB).
Zur Berechnung der Nullstellen siehe z.B. die Ausführungen zur Riemann-Siegel Formel
(mit Programm-Code) auf der Netz-Seite des Verfassers.
Das folgende „ari.bas“-Programm berechnet li(xρ) für 10 1 bis 10 m ,wobei das gewünschte m
an der Eingabeaufforderung anzugeben ist. (Setzt man (statt x:= 10**j) x:=m, kann man das
gewünschte x auch direkt eingeben.)
Etwas verkompliziert wird das Programm dadurch, dass infolge von Einschränkungen bei der
Dimensionierung des Nullstellen-Vektors ti[ ] die Nullstellen sukzessive in Blöcken à 50.000
geladen werden.
12
function rr(m:integer);
# x = 101 bis 10m
# Berechnet Σ 2*Re{li(x^rho)} mit bis zu 2 Mio Nullstellen,
# die in der Festplatten-Datei „zeros“ gespeichert sind
var
h,hh,ho,i,j,k,o,v: integer;
z,zr,zi,c,d,e,g,lnx,r,s,t,x,xw: real;
ur,ui,kr,ki,kr0,ki0,kg,kq,k2,sr,si,sli: real;
ti:array[50011] of real;
begin
ho:=2*10**6
# Festlegung der verwendeten Nullstellen-Anzahl
for j:=1 to m do
#0
open_read(z,"i:\zeros");
x:=10**j;
kg:=10**(-12);lnx:=log(x); xw:=2*sqrt(x)/lnx; # kg: Abbruchschwelle
sli:=0; h:=0; o:=40;
# o: Größe der Nullstellen-Datei / 50.000
while h<1+o do
#1
for v:=1 to 50000 do; readln(z,t); ti[v]:=t; end;
for i:=1 to 50000 do
#2
hh:=h*50000+i; if hh>ho then break; end;
t:=ti[i];
r:=t*lnx; d:=0.25+t**2; g:=lnx*d;
c:=cos(r); s:=sin(r);
zr:=xw*(0.5*c+t*s); zi:=xw*(0.5*s-t*c);
ur:=zr/d;
ui:=zi/d;
kr:=1; ki:=0; sr:=1; si:=0; k2:=1;
#3
for k:=1 to 1000 do
kr0:=k*(kr*0.5+ki*t); ki0:=k*(ki*0.5-kr*t);
kr :=kr0/g;
ki :=ki0/g;
kq:=kr**2+ki**2;
#
if kq<kg then break; end;
# Abbruchkriterien
if kq>k2 then break; end;
#
k2:=kq;
sr:=sr+kr;
si:=si+ki;
end;
#3
e:=ur*sr-ui*si; sli:=sli+e;
end;
#2
h:=h+1; if hh>ho then break; end;
end;
#1
writeln(" x : ",x:30);
writeln("Su. 2*Re{li(x^rho)}: ",sli:12:4," mit “,hh:9:1,“ Nullst.“);
writeln();
close(z);
end;
#0
end.
Ergebnisse mit m = 7 (und 128 Stellen Gleitkomma-Genauigkeit):
==> set_floatprec(128).
==> rr(7).
x:
100000
Su. 2*Re{li(x^rho)}: -4.6413 mit 2 Mio. Nullst.
(Exakter Sollwert)∗)
(-4.653.....)
x:
1000000
Su. 2*Re{li(x^rho)}: 29.8228 mit 2 Mio. Nullst.
(29.745.....)
x:
10000000
Su. 2*Re{li(x^rho)}: 90.5460 mit 2 Mio. Nullst.
(90.412.....)
∗)
aus Formel (**) ‚rückwärts’ errechnet.
13
Weitere Einzelheiten sollen an Hand von Grafiken erläutert werden, die um Details zu zeigen,
mit einer Auflösung von 1/103 und unter Berücksichtigung der ersten 103 Nullstellen
berechnet wurden.
0,8
∞
10 3
∑ li (xρ )
∫ t⋅( t −11)⋅ln ( t) dt
0,6
k
2
k =1
x
0,4
0,2
0
1,5
2
2,5
3
3,5
4
4,5
5
x
5,5
-0,2
-0,4
-0,6
-0,8
Bild 1.
Das Bild 1. zeigt den sägezahnförmigen Verlauf von Σ li(xρ) mit dem typischen
Überschwingen in der Nähe der Sprungstellen. Die Sprünge treten – wie gefordert – genau
dann auf, wenn x eine Primzahlpotenz ist; die Höhe des Sprunges an der Stelle ps ist gleich
1 / s. (Der hier gezeigte Vorzeichenwechsel an den Sprungstellen tritt natürlich nicht immer
auf.)
Die rote Kurve verdeutlicht, dass das (mittels numerischer Integration berechnete) Integral
nur für kleine x-Werte von Bedeutung ist.
14
4
10 3
3,5
J * ( x ) = li( x ) −
∑ li(x
ρk
∞
) − ln( 2) +
k =1
3
∫ t⋅( t −dt1)⋅ln( t )
2
x
2,5
2
1,5
J(x ) =
1
∞
∑ 1n ⋅π( x
1
n
)
n =1
0,5
x
0
1,5
2
2,5
3
3,5
4
4,5
5
5,5
-0,5
Bild 2.
Um für J(x) gemäß Definition und J*(x) gemäß der Riemann’schen Formel zwei
unterscheidbare Verläufe zu erhalten, ist J*(x) in Bild 2. um 0,1 nach links und um 0,1 nach
oben verschoben dargestellt. Das zeigt, dass die asymptotische Reihendarstellung für li(xρ)
(siehe oben) hier auch für die kleinsten vorkommenden x-Werte gut brauchbar ist. Wie man
sieht, gilt die Formel J*(x) sogar für x < 2.
Die Schwingungen von J*(x) in der Nähe der Sprungstellen legen nahe, im Fall großer xWerte, die Berechnung von π(x) möglichst in der Mitte zwischen zwei Primzahlen oder für
gerades x auszuführen.
Bild 1. und Bild 2. suggerieren, dass der Sprung an der Stelle x = ps für J*(x) übergangslos
stattfindet (so wie es bei J(x) der Fall ist). In Wirklichkeit ist die Gleichung (∗) – also
J*(x) = J(x) – an den Sprungstellen als Grenzwert zu verstehen, denn es ist
J*(ps) = (J*(ps – ε) + J*(ps + ε)) / 2, wobei ε → 0 für T→ ∞ .
Somit ist Σ li(2ρ) = 0 und die mit nur 103 Nullstellen durchgeführte Berechnung bestätigt das
mit dem Wert von – 0,0043 bereits in guter Näherung.
Als nächstes soll veranschaulicht werden, wie sich li(xρ) sich für jedes einzelne ρ in
Abhängigkeit von x entwickelt.
15
x ⋅ t1
0,3
ln(x)⋅(σ2 + t12 )
0,2
Re{li (xρ1 ) }
0,1
0
2
12
22
32
42
52
62
72
ρ20
Re{li(x ) }
-0,1
-0,2
-0,3
Bild 3.: Verläufe von Re{li(xρ)} für ρ1 = 0,5 + j⋅14,1347... und ρ20 = 0,5 + j⋅77,1448...
16
x
Als wesentliche qualitative Information vermittelt Bild 3., dass li(xρ) eine Schwingung
darstellt, deren Amplitude mit wachsendem x zunimmt, während die Frequenz zugleich
abnimmt. Die erste Nullstelle ρ1 besitzt die größte Amplitude; d.h. die Bedeutung der ρk
bezüglich des Ergebnisses der Summation nimmt „im Mittel“ mit wachsendem k – also
steigendem Imaginärteil von ρk – ab.
Für quantitative Aussagen ist die Untersuchung des Term
x σ ⋅{cos ( t ⋅ln x ) ⋅ σ⋅ln x + sin ( t ⋅ln x ) ⋅ t ⋅ln x }
( σ⋅ln x ) 2 + ( t ⋅ln x ) 2
c
maßgeblich, während der Faktor
=
x
ln ( x )⋅( 0.25 + t 2 )
∑ (ln(kx ! ))
ρ
k
⋅ { 0,5⋅ cos( t⋅ln ( x )) + t⋅sin ( t⋅ln( x )) }
kaum eine Rolle spielt (wie auch weiter unten
k =0
noch gezeigt wird.)
Die max. Amplitude (einer Halbschwingung) wird erreicht, wenn {...} den Wert t + ε hat (mit
ε → 0 für k → ∞): Amax(x) ≈ ±
x
ln ( x )⋅t
(siehe blaue „Einhüllende“ in Bild 3.) Das Minimum
von Amax(x) liegt bei x = 7,389.
Von Interesse sind die Nulldurchgänge der Schwingungskurve. Diese treten auf, wenn
{....} = 0 ist, also 0,5⋅cos(t⋅ln x) = – t⋅sin(t⋅ln x). Wegen des dominierenden Sinus-Terms folgt
sin(t⋅ln x) ≈ 0 und somit t⋅ln x ≈k⋅π. Daraus lässt sich für ein beliebig vorgegebenes x die
größte Nullstelle x0 mit x0 < x bestimmen: k = (t⋅ln x / π) + ∆ und somit x0,k = ek⋅ π / t. Ist k
gerade, liegt x > x0 in der positiven Halbwelle; anderenfalls in der negativen. Durch
Verringern bzw. Vergrößern von k folgen alle weiteren Nullstellen. (∆ << t⋅ln x /π (z.B. 0.01).
Nach diesen Betrachtungen soll nun die Leistungsfähigkeit des Verfahrens an einigen
Beispielen getestet werden. Zugrunde gelegt wird dabei die Gleichung (∗∗):
T
π(x) ≈ π*(x) = li(x) – 2⋅ ∑ Re {li( x
ρk
k =1
o
)} – ln(2) –
∑ 1n π (x
1
n
)
n=2
In Bild 4. (siehe folgende Seite) zeigt der rote Linienzug den Verlauf von π(x) im Intervall
[104, 104 + 100]. Die blaue Kurve gibt die mit einer Schrittlänge von 0,25 berechneten Werte
π*(x) wieder, wobei T = 50.000 Nullstellen der Zeta-Funktion einbezogen wurden.
Offensichtlich lassen sich alle π(x)-Werte korrekt bestimmen, wenn π*(x) auf die jeweils
nächstgelegene natürliche Zahl auf- bzw. abgerundet wird; ausgenommen die Sprungstellen
von π(x) – wenn also x eine Primzahl ist.
Bild 5. ist für den Bereich 106 bis 106 + 100 analog zu Bild 4. aufgebaut, wobei allerdings 10mal so viele – also 500.000 – Nullstellen berücksichtigt wurden. Die blaue Kurve nähert π(x)
besonders gut im Bereich (relativ) großer Primzahl-Lücken an, und π(x) kann (mit der
gleichen Einschränkung wie oben) problemlos bestimmt werden – insbesondere, wenn der
Wert von π*(x) für x = (pi + pi+1) / 2 berechnet wird.
Zu den beiden parallel verlaufenden dünn gezeichneten Linien: Die obere zeigt π*(x) mit nur
50.000 Nullstellen berechnet – also die Fortsetzung von Bild 4. zwei Zehnerpotenzen später.
Die Näherung ist zwar immer noch recht gut; aber im Grunde ist es eher eine „Trendlinie“.
Die untere (grüne) Linie berücksichtigt ebenfalls 50.000 Nullstellen, allerdings ist der
Summenterm in der Entwicklung von li(xρ) zu 1 gesetzt. Das bedeutet eine erhebliche
Vereinfachung der Rechnung offenbar ohne einen gravierenden Verlust an Information.
17
π(x) – π(104)
π*(x) –π(104)
(mit 5⋅104 Nullstellen)
x – 104
Bild 4. (π(104) = 1229)
8
π(x) – π(106)
π*(x) – π(106) (mit 5⋅105 Nullstellen)
7
6
mit 5⋅104 Nullstellen
5
4
3
(*) mit 5⋅104 Nullstellen
2
1
x – 106
0
0
10
20
30
40
50
60
70
80
90
100
Bild 5. (π(106) = 78498)
Die beiden Bilder zeigen insbesondere, dass zur exakten Feststellung von π(x) die Anzahl der
zu berücksichtigenden Nullstellen in der Größenordnung von x liegt! Möglicherweise lassen
sich aber aus dem Verlauf von Σ li(xρ) in Abhängigkeit von T (= Anzahl der berücksichtigten
18
Nullstellen) Rückschlüsse bezüglich des Grenzwert (T = ∞) ziehen. Die Bilder 6. und 7.
zeigen solche Verläufe.
31
2⋅
30,5
k
∑ Re {li(xρ )}
x = 106
k
1
30
29,5
Sollwert (=29,744)
29
Gleitender Durchschnitt
28,5
28
27,5
k
27
0
200000
400000
600000
800000
1000000
1200000
Bild 6.: Verlauf von Σ li(xρ) als Funktion der Nullstellen-Anzahl k für x = 106
78.498)
101
1400000
(π(x) =
k
2⋅
99
∑ Re{li(xρ )}
k
x = 108
1
Sollwert (= 95,629)
97
95
93
Gleitender Durchschnitt
91
89
87
k
85
0
200000
400000
600000
800000
1000000
1200000
1400000
Bild 7.: Verlauf von Σ li(xρ) als Funktion der Nullstellen-Anzahl k für x = 108 (π(x) =
5.761.455)
19
Aus beiden Bildern wird ersichtlich, dass Σ li(xρ) bereits mit relativ wenigen Nullstellen eine
gute Annäherung an den „Sollwert“ ( T = ∞) erreicht, sich dann allerdings nicht gerade
‚zielstrebig’ dem Sollwert nähert. Eine gewisse Orientierungshilfe kann der gleitende
Durchschnitt bieten, denn dieser nähert sich dem Sollwert regelmäßig asymptotisch an.
Um mittels (**) den exakten Wert von π(x) bestimmen zu können, darf der errechnete Wert
π*(x) höchstens um 0,5 vom Ist-Wert abweichen, also π(x) = π*(x) + 0,5. Wie viele
Nullstellen sind in die Rechnung einzubeziehen, damit diese Forderung mit Sicherheit erfüllt
ist?
Vorliegend wurde (beginnend mit x = 100) π*(x) für gerades x mit jeweils x Nullstellen der
Zeta-Funktion berechnet. Der erste Fehler trat bei x = 303. 548 auf. D.h. um π(x) zuverlässig
zu berechnen, benötigt man mehr als x Nullstellen, was die ‚praktischen’ Grenzen des
Verfahrens aufzeigt.
(In der Literatur findet man einen Wert von 1,2⋅x als Mindest-Anzahl, um einen Fehler < 0,5
durchgängig sicherzustellen.)
Fazit: Re{li(xρ)} stellt eine Schwingung dar, deren Frequenz und Amplitude von x und ρ
abhängt. Die faszinierende Eigenschaft dieser Schwingungen ist, dass deren Überlagerung
einen sehr glatten Verlauf ergibt, mit Ausnahme der Stellen x = pm, an denen ein Sprung der
Höhe 1 / m auftritt (s. Bild 1).
Um den Verlauf von π(x) mit einer max. Differenz < 0,5 nachzubilden, müssen allerdings
teilweise mehr als x Nullstellen der Zeta-Funktion in die Rechnung einbezogen werden.
Wegen dieses Aufwandes ist das Verfahren im Vergleich zum kombinatorischen Verfahren
bei weitem nicht konkurrenzfähig, wenn es um den genauen Wert von π(x) geht – und nicht
etwa um gute Näherungen.
20
b) Weiterentwicklung der analytischen Verfahren
Den entscheidenden Anstoß zur Weiterentwicklung gaben 1987 J. Lagarias u. A. Odlyzko mit
ihrem Beitrag „Computing π(x): An Analytic Method“.
Ausgangspunkt ist/bleibt die Identität J(x) =
∑
∑
1
1 =
1 ⋅π( x m )
m
m
m ≥1
pm≤x
(wobei der
Vereinfachung halber x keine Primzahlpotenz sei) und daraus π(x) = J(x) –
∑
m≥2
1
1 ⋅π( x m ) .
m
Die von Riemann entwickelte Formel folgt letztlich aus
J(x) =
∑
n≤x
Λ(n)
= 1
ln( n )
2⋅π⋅i
σ+i∞
x s ln ζ(s) ds und das schlechte Konvergenzverhalten dieses
s
σ −i∞
∫
Integrals bedingt die oben beschriebene begrenzte Praxistauglichkeit der „expliziten“ Formel.
Die beiden o.g. Autoren verallgemeinerten die Formel für J(x) zu
σ + i∞
∫ φˆ (s)⋅ln ζ(s) ds + ∑ m1 ⋅ (χ(p ) – φ(p ))
J(x) = 1
m
2 π⋅i
Darin bedeutet χ(r) =
σ − i∞
p
1
r<x
½
0
r=x
r>x
(∗∗∗∗)
m
m
und
∞
∫
φ̂ (s) = φ (r)⋅r s – 1dr
die Mellin-Transformierte von φ und
0
σ+i∞
φ(r) = 1
2 π⋅i
∫ φˆ (s)⋅r
–s
ds die inverse Mellin-Transformierte.
σ −i∞
(Die Mellin-Transformation ist eine Variante der Laplace-Transformation und spielt im
Zusammenhang mit der Zeta-Funktion allgemein eine wichtige Rolle.)
s
Die von Riemann benutzte Formel für J(x) ergibt sich im Fall φ̂ (s) = x → φ(pm) = χ(pm).
s
Die Funktion φ(r) ist nun so zu wählen, dass
• das Integral in (∗∗∗∗) möglichst gut konvergiert (rel. wenige Nullstellen erforderlich)
und
• die Summe nicht von 0 bis x zu erstrecken ist, sondern nur über eine Umgebung von
x: x1 < x < x2, da außerhalb dieser Grenzen χ(pm) – φ(pm) ≈ 0 .
σ + iT
M.a.W., es muss gelten: J(x) ≈ J*(x) = 1
2 π⋅i
∫ φˆ (s)⋅ln ζ(s) ds + ∑ m1 ⋅ (χ(p ) – φ(p ))
m
σ −i T
x1 < p m < x 2
Das führt natürlich nur zu verwertbaren Ergebnissen, wenn T , x1 und x2 sowie die RestTerme mittels einer genauen Analyse so festgelegt werden, dass | J*(x) – J(x)| < 0,5 ist.
21
m
Dabei ist zu beachten, dass T und die Länge des Intervalls [x1, x2] sich gegenseitig bedingen;
d.h. eine Verkleinerung des einen Wertes hat die Vergrößerung des anderen zur Folge.
Soweit die sehr kursorische Beschreibung des Verfahrens. Eine detaillierte Darstellung
(einschließlich eines geeigneten „Mellin-Paares“ und der Festlegung der Parameter) findet
sich z.B. in der Dissertation von W. Galway: „Analytic Computation of the Prime Counting
Function“, 2004.
Die Hauptpunkte der Bestimmung von J*(x) sind nun
1. Berechnung von ζ(σ + i⋅t) mit σ > 1 für alle t < T (t: Imaginär-Teil der Nullstellen)
2. Die (numerische) Integration von φ̂ (s) ⋅ ln ζ(s) (ggf. nach weiterer Umformung)
3. Bestimmung aller Primzahlen im Intervall [x1, x2]
Jeder dieser Punkte stellt eine Herausforderung dar, wie die folgenden, ungefähren Angaben
zur Berechnung von π(1024) zeigen:
x2 – x1 ≈ 5⋅1015 (x2 > 1024)
T ≈ 21⋅109 → Anzahl NT ≈ 7⋅109
t-Werte auf mehr als 20 Dezimale genau; entsprechend ζ(s)-Werte
Trotz diesen hohen Aufwandes konnten Mathematiker der Uni Bonn in 2010 den (inzwischen
mehrfach bestätigten) Wert von π(1024) und in 2013 von π(1025) veröffentlichen. (Man
beachte den zeitlichen Abstand!)
Fazit: Solange sich noch kein „Standard-Algorithmus“ herauskristallisiert hat und für diesen
die ζ(s)-Werte in tabellarischer Form zur Verfügung stehen (so wie heute für die Nullstellen),
ist das weiterentwickelte analytische Verfahren als PC-Anwendung noch kaum tauglich.
π(1024) = 18.435.599.767.349.200.867.866
Zum Vergleich nach Formel (∗∗) mit NT = 2⋅106:
li(x)
= 18.435.599.767.366.347.775.144,15
2⋅10 6
–
∑ li(xρ
)=
+ 1.735.186.435,44
π( x n ) =
– 18.805.897.694,67
k
k =1
∞
–
∑
n =2
1
n
– ln(2)
1
=
– 0,69
π(10 ) ≈ 18.435.599.767.349.277.063.884
24
Die Anstrengungen, auch die letzten Dezimale exakt zu bestimmen, werden dadurch
gerechtfertigt, dass in Verfolgung dieses Ziels u. a.
• das Verständnis des Zusammenhangs zwischen den Primzahlen und der ZetaFunktion verbessert wird und die Techniken zur numerischen Behandlung der
komplexen Integrale verfeinert werden,
• neue Verfahren zur Berechnung von ζ(σ + i⋅t) auch abseits von σ = ½
entwickelt werden und
• die Effizienz der Siebverfahren weiter verbessert wird.
22
Anhang I-A1
Sieb zur Bestimmung aller Primzahlen im Intervall nd [= no – nu]
Das seit über 2000 Jahren bekannte Sieb des Eratosthenes ist (mit mancherlei durch den
Rechnereinsatz möglich gewordenen Vorkehrungen zur Beschleunigung) auch heute noch das
Verfahren der Wahl, wenn über einen größeren Bereich hinweg explizite Primzahllisten
benötigt werden (z.B. bei der Suche nach Primzahlzwillingen oder großen Primzahllücken).
Das nachstehende Programm ermittelt und speichert unter einer 2,4 GHz-CPU alle
Primzahlen im Intervall [0,10 9] in rd. 7,2 Sekunden; in [10 16,1016 + 10 9] sind es
– wegen der größeren Anzahl der benötigten Sieb-Primzahlen < Wurzel no (s.u.) – 13,1 Sek.
Das Programm enthält z.B. keine komplizierten Bit-weisen Operationen, wie sie manchmal
zur Beschleunigung und zur Einsparung von Arbeitsspeicher eingesetzt werden und sollte
daher leicht auf andere Programmierplattformen übertragbar sein.
Zur Funktionsweise:
Teil 1 dient dazu, die zum Sieben erforderlichen Primzahlen kleiner Wurzel no
bereitzustellen. Das geschieht mit einem „klassischen“ Sieb des Eratosthenes, wobei hier die
geraden Zahlen gänzlich unbeachtet bleiben und die Vielfachen der ungeraden Primzahlen mit
der Schrittweite 2p (jeweils ab p 2) gestrichen werden (s(j) = 1).
Nachdem dies mit allen Primzahlen kleiner no1/4 durchgeführt wurde, gilt: s(i) = 0 → i ist
Primzahl und die „Sieb-Primzahlen“ (Anzahl: uo) stehen im Speicher p() zur Verfügung.
In Teil 2 werden zunächst alle zum Modul m = 2⋅3⋅5⋅7⋅...⋅pf teilerfremden Zahlen < m
in s() markiert und nach aufsteigender Größe in e() gespeichert (Anzahl: e).
Nach Löschen und Umdimensionieren von s() auf die Größe des Siebintervalls nd können nun
die zu m teilerfremden Zahlen im gesamten Siebintervall – quasi als „potentielle“ Primzahlen
– eingetragen werden. (Das häufig anschaulich mit „Zahlenrad“ oder auch „Stempel“
bezeichnete Verfahren vermeidet zu einem großen Teil die sonst unvermeidlichen
Mehrfachstreichungen von zusammengesetzten Zahlen, was eine entsprechende Zeitersparnis
zur Folge hat; ein „Sieb des Eratosthenes“ im engeren Sinn ist das allerdings nicht mehr.
Da m mit zunehmendem f (→ pf) schnell groß wird und damit der Aufwand zur Erstellung
des Zahlenrades stark ansteigt, sollte f nicht zu groß gewählt werden; f = 7 dürfte ein guter
Kompromiss sein. Größere Werte könnten in Betracht kommen, wenn das einmal erstellte
Zahlenrad für viele aufeinanderfolgende Siebungen Verwendung finden kann.)
In Teil 3 werden nach der „klassischen“ Methode von den zum Modul m teilerfremden
Zahlen diejenigen gestrichen (s(j) = 0), die echte Vielfache der Primzahlen > pf sind.
Die Fallunterscheidung im If-Befehl sorgt dafür, dass – in Abhängigkeit von der Untergrenze
des Siebintervalls – für jede Siebprimzahl die korrekte Startzahl bereitgestellt wird.
Nach Abschluss der Prozedur gilt: s(i) = 1 → i ist Primzahl (Anzahl: w).
(Der ganz überwiegende Anteil der benötigten Rechenzeit entfällt auf Teil 3. Weitere
Optimierungen zu einer bedeutenden Verminderung der Rechenzeit müssten sich daher auf
diesen Punkt konzentrieren.)
Anm.: Da es nur um die Bestimmung der ungeraden Primzahlen geht (die geraden sind ja
bekannt), lässt sich der Speicherbedarf ersichtlich mittels einer einfachen Modifikation (im
nachstehenden Programm-Code rot geschrieben) halbieren, was zu einer Verdopplung des
Siebintervalls genutzt werden könnte (und auch eine kleine Verkürzung der Rechendauer
1
bewirkt). Das hat aber zur Folge, dass die Primzahl i nicht mehr an der Stelle s(i) gespeichert
ist, sondern bei Bedarf mit i = 2⋅i + 1 umgerechnet werden muss, was lästig sein kann.
Bei der Vorgabe der unteren Grenze des Siebbereichs (nu) und der Sieblänge (nd) sind zwei
für die Praxis unerhebliche Einschränkungen zu beachten (, die sich zudem erf. durch
Überspringen von Teil 2 leicht beheben lassen):
nu:(= 0 oder 20 ≤ nu ≤ 1018); gerade
nd:(400 ≤ nd ≤ 2⋅109); gerade
DIM p(1 TO 10^8) AS LONG
DIM s(1 TO 10^5) AS BYTE
DIM e(1 TO 10^5) AS LONG
‘Primzahl-Speicher
‘Siebvektor
‘Speicher für prime Restkl. mod m
'Teil 1 ------- Primzahlliste bis n o
-------nu=10^12: nd=10^9
'Vorgabe des Siebbereichs
no=nu+nd: now=INT(SQR(no))
REDIM s(1 TO now+100): noww=INT(SQR(now))
FOR h=3 TO noww STEP 2
IF s(h)=1 THEN ITERATE ELSE h2=h+h: hq=h*h
FOR j=hq TO now STEP h2: s(j)=1: NEXT j
NEXT h
u=1: FOR i=3 TO now STEP 2: IF s(i)=0 THEN u=u+1: p(u)=i
NEXT i: p(1)=2: uo=u
PRINT "UG:";nu,"Intervalllaenge ND:";nd;" OG:"no
PRINT "Anzahl "Sieb-Primen" < Wurzel OG: ";uo
'Teil 2 -- Belegung von s() mit primen Resten mod m ---m=1: f=7: e=0
‘1 < f < 8; sonst Vektor e() vergrößern
FOR i=1 TO f: m=m*p(i): NEXT i: REDIM s(1 TO m+100)
FOR i=2 TO f: h=q(i): h2=h+h
FOR j=h TO m STEP h2: s(j)=1: NEXT j
NEXT i
FOR i=1 TO m: IF s(i)=0 THEN e=e+1: e(e)=i\2
NEXT i: nd=nd\2
‘Zahlenrad fertig
ru=nu\m: ro=no\m: REDIM s(-m TO nd+m) ‘ “\”: Ganzzahldivision
FOR i=ru TO ro: g=(m*i-nu)\2
FOR j=1 TO e: r=g+e(j): s(r)=1: NEXT j
NEXT i
‘prime Reste mod m in s() markiert
PRINT "Modul m:"m;"
Anz. prime Restklassen:"e
IF nu=0 THEN s(1)=0: FOR i=1 TO f: s(p(i)\2)=1: NEXT i
'Teil 3 --------- mit Primen > pf sieben --------FOR i=f+1 TO uo: p=p(i): p2=p+p: pq=p*p
IF pq>nu THEN ug=pq-nu ELSE ug=p2–(nu–p)MOD p2
ug=ug\2
FOR j=ug TO nd STEP p2\2: s(j)=0: NEXT j
NEXT i
IF nu=0 THEN w=1 ELSE w=0
FOR i=1 TO nd STEP 2\2: w=w+s(i): NEXT i
PRINT "Anzahl Primen in ND: "w
2
Anhang I-A2
#OPTION LARGEMEM32
'Gibt 3 GB A.-Speicher frei
DEFEXT Z
DEFQUD S,X
'< 9*10^18
DEFLNG A,B,C,E,H,I,J,M,N,P,R,V'< 2*10^9
FUNCTION PBMAIN()
DIM p (0 TO 100) AS LONG
'Primzahlliste
DIM pi(0 TO 100) AS LONG
'π
π(y)-Datei
DIM c (0 TO 100) AS LONG
'temp.Speicher
DIM d (0 TO 100) AS BYTE
'Siebvektor für Φ(y,a)
DIM f (0 TO 100) AS INTEGER
'µ
µ(i) u. Sieb für m
LINE INPUT "N =";z$: z = VAL(z$) 'Eingabe N
x = INT(z+0.005)
IF x < 2 THEN PRINT "N =";x, "Pi(N) =";0 :GOTO 1111
IF x > 1.442*10^17 THEN PRINT "N > 2^57 !":GOTO 1111'bei 3 GB A.-Sp.
ze = .4725##
INT(x^ze)
INT(SQR(x\aa))
INT(x^(1/5))
INT(x^(1/4))
rr: IF x > 10^16
IF npi< 10^6
nh = npi: IF nh MOD 2 = 1 THEN
aa
cc
vv
vv3
npi
=
=
=
=
=
'Vorgabe;(0,4 < ze < 0,5)
: bb = INT(x^(1/3))
: ee = INT(SQR(x))
: rr = x\aa 'rr muss < 2*10^9 wegen
'max. Länge von d()
THEN npi = 1.65*ee 'ee <= npi <= rr
THEN npi = 10^6
nh = nh+1
'nh <= npi; nh gerade
'----------- Erstellen einer Primzahltabelle bis aa und
'
einer π(y)-Datei für y <= npi <= rr ----------------REDIM d(0 TO npi+100): REDIM pi(1 TO npi+100): zim1 = TIMER
ew=INT(SQR(npi))
FOR i = 3 TO ew STEP 2
′Sieb des Eratosthenes für
IF d(i)=1 THEN ITERATE
′ungerade Zahlen
i2=i+i: iq=i*i
FOR j=iq TO npi STEP i2: d(j)=1: NEXT j
NEXT i: re=1
FOR i = 3 TO aa STEP 2
'Bestimmung der Größe von p()
IF d(i)=0 THEN re=re+1
NEXT i: REDIM p(1 TO re+100): r=1
FOR i = 3 TO npi STEP 2
IF d(i)=1 THEN ITERATE
r=r+1: pi(i)=r
' π(y)-Datei
IF i <= aa THEN p(r)=i
NEXT i: p(1)=2: pi(1)=0: pi(2)=1
FOR i = 1 TO npi: IF pi(i)=0 THEN pi(i)=pi(i–1)
NEXT i
'----------------------------------------------------------------IF x <= npi THEN PRINT "N =";x, "Pi(N) ="; pi(x): GOTO 1111
a = pi(aa): b = pi(bb): c = pi(cc): e = pi(ee) ' Kenngrößen
v1 = pi(vv): v2 = pi(INT(SQR(aa))):
v3 = pi(vv3)
jm = pi(INT(SQR(rr))): jn = pi(nh–1)
PRINT ,,"ze: ";ze : PRINT "ee: "; ee,"aa: "; aa,"rr: "; rr
PRINT "e : "; e ,,"a : "a, "npi:"; npi: PRINT
1
'--------- Ber. der Möbius-Funktion in [1 bis aa] ---------------REDIM f(0 TO aa+100): MAT f()=CON
'Alles auf ‘1’ gesetzt
FOR i = 1 TO v2: p = p(i)
'v2 = π(aa^(1/2))
FOR j = p^2 TO aa STEP p^2: f(j)=0: NEXT j
NEXT i
'nicht-quadratfreie j sind markiert (= 0)
FOR i = 1 TO a: p=p(i)
'a = π(aa)(= π(x t))
FOR j = p TO aa STEP p: f(j)=–f(j): NEXT j
NEXT i
'--------------- Berechnung von S0 -------------------------------s0=0: sr=1: r1=1: REDIM d(0 TO rr+100): MAT d()=CON
FOR i = 1 TO 10
'v0 so,dass sr < aa aber sr*p(v0+1) > aa ist
sr=sr*p(i): r1=r1*(p(i)–1)
IF sr > aa THEN v0=i–1: sr=sr\p(i): r1=r1\(p(i)–1): EXIT
NEXT i: REDIM c(0 TO rr)
FOR i = 2 TO rr STEP 2
: d(i)=0: NEXT i
FOR i = 2 TO aa STEP 2
: f(i)=0: NEXT i
FOR j = 2 TO v0: ps=p(j)
FOR i = ps TO rr STEP 2*ps: d(i)=0: NEXT i
FOR i = ps TO aa STEP 2*ps: f(i)=0: NEXT i
'wegen S1 wird c() bis rr gespeichert
NEXT j: c(0)=0: ra=0
FOR i = 1 TO rr: ra=ra+d(i): c(i)=ra: NEXT i
FOR i = 1 TO aa STEP 2
IF f(i)=0 THEN ITERATE
xi=x\i: r=xi MOD sr
sc=r1*(xi\sr): s0=s0+f(i)*(sc+c(r))
NEXT i
PRINT "v0: ";v0, "v1: ";v1, "v2: ";v2, "v3: ";v3: PRINT
PRINT USING$("&#","s0:
",s0)
'------------- Berechnung von S1 --------------------------------v=v0+1
'Für v0+1 u.v0+2 werden die in c() gespeicherten Werte
'genutzt.
s1=0: IF aa MOD 2=0 THEN ao=aa–1 ELSE ao=aa
pv=p(v):f(pv)=0:pq=pv^2
FOR i = pq TO aa STEP 2*pv: f(i)=0: NEXT i
mv=aa\pv +1: xp=x\pv
'd() ist bereits mit p(v-1) gesiebt
FOR m = ao TO mv STEP– 2
IF f(m)=0 THEN ITERATE
rz=xp\m: s1=s1–f(m)*c(rz)
NEXT m
v=v0+2
ps=p(v-1):d(ps)=0:iu=ps^2: FOR i=iu TO rr STEP 2*ps:d(i)=0:NEXT i
pv=p(v) :f(pv)=0:pq=pv^2: FOR i=pq TO aa STEP 2*pv:f(i)=0:NEXT i
mv=aa\pv +1: xp=x\pv
FOR m = ao TO mv STEP–2
IF f(m) = 0 THEN ITERATE ' Φ(y,a) = Φ(y,a-1)– Φ(y\pa,a-1)
rz=xp\m: rzp=rz\ps: s1=s1–f(m)*(c(rz)–c(rzp))
NEXT m: REDIM c(0 TO 10)
FOR v = v0+3 TO v1
'v1 = π(x^(1/5))
ps=p(v-1):d(ps)=0:iu=ps^2: FOR i=iu TO rr STEP 2*ps:d(i)=0:NEXT i
pv=p(v) :f(pv)=0:pq=pv^2: FOR i=pq TO aa STEP 2*pv:f(i)=0:NEXT i
mv=aa\pv +1: xp=x\pv
IF xp\ao > pq THEN ru=pq: h = pi(pq)–v+2 ELSE ru=pv+2: h=2
2
FOR m = ao TO mv STEP–2
IF f(m) = 0 THEN ITERATE
rz=xp\m
IF rz < ru THEN s1 = s1–f(m)*h: ITERATE
IF rz < pq THEN s1 = s1–f(m)*(pi(rz)–v+2):ITERATE 'rz < aa
FOR j = ru TO rz STEP 2: h = h+d(j): NEXT j
s1=s1–f(m)*h: ru = rz+1: IF ru MOD 2 = 0 THEN ru = ru+1
NEXT m
NEXT v
PRINT USING$("&#","s1:
",s1)
'------------- Ber. von Φ2(x, a) ----------------------------FOR i = v1 TO c: p = p(i): pq = p^2
'c = π(rr^(1/2))
FOR j = pq TO rr STEP 2*p: d(j) = 0: NEXT j
NEXT i
'Es ist nur [aa bis rr] mit pv1 bis pc (< pa) zu sieben
sn= 0: ru = ee+1: IF u MOD 2 = 0 THEN ru = ru+1
h = 0: m = ee : IF m MOD 2 = 0 THEN m = m–1
FOR i = m TO aa+1 STEP–2
IF d(i) = 0 THEN ITERATE
'i ist in [aa bis rr] prim
rz = x\i
FOR j = ru TO rz STEP 2: h = h+d(j): NEXT j
sn = sn+h: ru = rz+1: IF ru MOD 2 = 0 THEN ru = ru+1
NEXT i
sz = (e–a)*(e–a+1)\2: sphi2 = sz+sn
'------------ Berechnung von S2 --------------------------------s2 = 0: r = 0: REDIM d(0 TO 100): REDIM c(1 TO 4*10^6)
FOR v = v1+1 TO v2
'v2 = π(aa^(1/2))
pv = p(v): f(pv) = 0
FOR i = pv^2 TO aa STEP 2*pv: f(i) = 0: NEXT i
mv = aa\pv + 1: DO WHILE f(mv) = 0: mv = mv+1: LOOP
xp = x\pv: hg = x\pv^3: IF hg MOD 2 = 0 THEN hg = hg–1
FOR i = pi(mv) TO pi(hg)
rz = xp\p(i)
'rz > ee
IF rz <= nh THEN s2 = s2+pi(rz) ELSE r = r+1: c(r)= rz–nh '*)
'rq < aa
h3 = INT(SQR(rz)): ho = pi(h3): h = 0
FOR j = v TO ho: rq = rz\p(j): h = h+pi(rq)–j+1: NEXT j
s2 = s2+h
NEXT i
rv=(2–v)*(pi(hg)–pi(mv)+1): s2=s2+rv 'rv: Summe der (2-v)-Werte
FOR m = hg+2 TO aa STEP 2
IF f(m) = 0 THEN ITERATE
rz = xp\m: s2 = s2–f(m)*(pi(rz)–v+2)
NEXT m
'rz < aa
NEXT v
PRINT USING$("&#","s2:
",s2)
'------------- Berechnung von S3 ---------------------------------s3 = 0: ERASE f()
FOR v = v2+1 TO v3
'v3 = π(x^(1/4))
pv=p(v): xp=x\pv: hg=pi(x\pv^3)
'ze < 0,4 => x\pv^3 > aa
FOR i = v+1 TO hg
rz = xp\p(i)
'rz > ee
IF rz <= nh THEN s3=s3+pi(rz) ELSE r=r+1: c(r)=rz–nh
'*)
h3 = INT(SQR(rz)): ho = pi(h3): h = 0
'*):π
π(y)-Tabelle nicht lang genug: in c()speichern; Auswertung unten
3
FOR j = v TO ho: rq = rz\p(j): h = h+pi(rq): NEXT j'rq < aa
hj = ho*(ho–1)–((v–1)*(v–2)): s3 = s3+h–hj\2
' hj\2: Summe der (1–j)-Werte
NEXT i
FOR i = hg+1 TO a: rz=xp\p(i): s3=s3+pi(rz): NEXT I
'rz<ee
NEXT v
sz1=2*a*(v3–v2)–(a+2)*((v3*(v3+1)–v2*(v2+1))/2) 'Summe aller (2-v)
sz2=(v3*(v3+1)*(2*v3+1)–v2*(v2+1)*(2*v2+1))/6
'zwischen v2 und d
s3 = s3 + sz1 + sz2
'------------------- Berechnung von S4 ----------------------------s4 = ((a–b)*(a–b–1))\2
s4 = s4+a*(b–c–(c*(c–3))\2 + (v3*(v3–3))\2)
s4 = s4+v3 - (v3*(v3-1)*(2*v3-1))\6 - b+(b*(b-1)*(2*b-1))\6
su=0
FOR i = v3+1 TO c: ru = x\(p(i)*aa): su = su+pi(ru): NEXT i
s4 = s4+a*su: su=0
'ru < aa
FOR i = c+1 TO b: ru = x\(p(i)^2) : su = su+pi(ru): NEXT i
'ru < aa
s4 = s4+su:
su=0
FOR i = v3+1 TO b: ru = INT(SQR(x\p(i))): su=su+pi(ru)^2: NEXT i
s4 = s4–su
'ru < aa
FOR i = v3+1 TO b: ru = INT(SQR(x\p(i))): xpi = x\p(i)
FOR j = i+1 TO pi(ru)
rq=xpi\p(j): rp=pi(rq): s4=s4+rp: IF rq < aa THEN s4=s4+rp
'rq < ee
NEXT j
NEXT i
'---------- Ber. der Beiträge der π(y) für y > nh zu S2 u. S3 ---IF r > 0 THEN
'r: Anzahl Zahlen in c()
ERASE pi(): ard = rr–nh: REDIM d(0 TO ard+100): MAT d() = CON
FOR j = 2 TO jm: p2 = p(j)+p(j): pq = p(j)*p(j) 'jm = π(rr^(1/2))
IF pq > nh THEN iu = pq–nh ELSE iu = p2–(nh–p(j)) MOD p2
FOR i = iu TO ard STEP p2: d(i) = 0: NEXT i
'd(i) = 1 => i ist prim
NEXT j
ARRAY SORT c() FOR r: h = 0: iu = 1: s3 = s3+jn*r
'jn = π(nh)
FOR j = 1 TO r: rj = c(j)
'c() ist aufsteigend sortiert
FOR i = iu TO rj STEP 2: h = h+d(i): NEXT i
s3 = s3+h: iu = rj+1: IF iu MOD 2 = 0 THEN iu = iu+1
NEXT j 'Achtung: Der mögliche Fall c(i) = c(i+1) ist nicht
END IF
'berücksichtigt und kann somit zu einem (leicht
'vermeidbaren) Fehler führen.
'-------------------Gesamtergebnisse-------------------------------PRINT USING$("&#","s3:
",s3)
sphi = s0 + s1 + s2 + s3 + s4
sp = sphi+a–1–sphi2: zim2 = TIMER
PRINT USING$("&#","s4:
",s4)
PRINT "
----------------"
PRINT USING$("&#","Phi (N, a): ",sphi):
PRINT
PRINT USING$("&#","Phi2(N, a): ",sphi2): PRINT
PRINT USING$("&#","N:
",x)
PRINT USING$("&#","Pi(N):
",sp) ;"
"; zim2 – zim1; "Sek."
1111
WAITSTAT
END FUNCTION
4
Herunterladen