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