Gunnar Bittersmann: Lösung

Beitrag lesen

@@Gunnar Bittersmann

An die lächerliche Geschwindigkeit – äh wahnsinnige Geschwindigkeit – äh enorme Schwierigkeit hab ich mich später gewagt; dazu später mehr.

Beim Itarator habe ich erst gerätselt, wie ich das n Elemente große Array, in welchem gesiebt wird, denn schrittweise erweitern sollte, wenn man an dessen Ende ankommt:

  • jeweils um die nächsten n Elemente: n → 2n → 3n → 4n …?
  • verdoppeln: n → 2n → 4n → 8n …?
  • oder gar um den Faktor der nächsten Primzahl: n → 2n → 6n → 30n …?

Gar nicht. Ich nutze eine andere Datenstruktur: ein zweidimensionales Array: in primes[i][0] stehen die Primzahlen; in primes[i][1] jeweils Vielfache davon. In primes[0][0] steht dann die 3; in primes[0][1] wird durchgezählt: 6, 9, 12, …

Wie schon zuvor, wird die 2 extra ausgeheben und nur noch ungerade Zahlen betrachet: current zählt munter durch: 3, 5, 7, 9, …

Die Vielfachen der vorher schon ermittelten Primzahlen werden solange hochgezählt, bis eine Zahl ≥ current rauskommt. Bei Gleichheit ist current ein Vielfaches, also keine Primzahl. → Nächstes current untersuchen.

Bei Ungleichheit: nächste Primzahl aus dem Array prüfen, ob current ein Vielfaches davon ist. Bei √current kann man aufhören. Wenn current bis dahin kein Vielfaches einer Primzahl war, ist current selbst eine Primzahl und wird zum Array hinzugefügt.

current | primes 3 | [[3, 6]] 5 | [[3, 6], [5, 10]] 7 | [[3, 6], [5, 10], [7, 14]] 9 | [[3, 9], [5, 10], [7, 14]] 11 | [[3, 12], [5, 10], [7, 14], [11, 22] 13 | [[3, 15], [5, 10], [7, 14], [11, 22], [13, 26]] 15 | [[3, 15], [5, 10], [7, 14], [11, 22], [13, 26]] 17 | [[3, 18], [5, 10], [7, 14], [11, 22], [13, 26], [17, 34]] 19 | [[3, 21], [5, 10], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38]] 21 | [[3, 21], [5, 10], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38]] 23 | [[3, 24], [5, 10], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46]] 25 | [[3, 27], [5, 25], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46]] 27 | [[3, 27], [5, 25], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46]] 29 | [[3, 30], [5, 30], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58]] 31 | [[3, 33], [5, 35], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62]] 33 | [[3, 33], [5, 35], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62]] 35 | [[3, 36], [5, 35], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62]] 37 | [[3, 39], [5, 40], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62], [37, 74]] 39 | [[3, 39], [5, 40], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62], [37, 74]] 41 | [[3, 42], [5, 45], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62], [37, 74], [41, 82]] 43 | [[3, 45], [5, 45], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62], [37, 74], [41, 82], [43, 86]] 45 | [[3, 45], [5, 45], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62], [37, 74], [41, 82], [43, 86]] 47 | [[3, 48], [5, 50], [7, 14], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62], [37, 74], [41, 82], [43, 86], [47, 94]] 49 | [[3, 51], [5, 50], [7, 49], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62], [37, 74], [41, 82], [43, 86], [47, 94]] 51 | [[3, 51], [5, 50], [7, 49], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62], [37, 74], [41, 82], [43, 86], [47, 94]] 53 | [[3, 54], [5, 55], [7, 56], [11, 22], [13, 26], [17, 34], [19, 38], [23, 46], [29, 58], [31, 62], [37, 74], [41, 82], [43, 86], [47, 94], [53, 106]]

☞ Implementierung: eratosthenesIteratorFunction.jsTestseite

function eratosthenesIteratorFunction()
{
	let current = 2, primes = [];
		
	return {
		next: function()
		{
			let isPrime;
			
			if (current === 2)
			{
				current--; /* following `current += 2` results in 3 */
				return { value: 2, done: false };
			}
			
			do
			{
				current += 2;
				
				if (current >= Number.MAX_SAFE_INTEGER)
				{
					return { done: true };
				}
				
				let sqrtCurrent = Math.sqrt(current);
				isPrime = true;
				
				for (let i = 0; isPrime && primes.length && primes[i][0] <= sqrtCurrent; i++)
				{
					while (primes[i][1] < current)
					{
						primes[i][1] += primes[i][0];
					}
				
					isPrime = (primes[i][1] !== current);
				}
			}
			while (!isPrime);
			
			primes.push([current, 2 * current]);						
			return { value: current, done: false };
		}
	};
}

Da bislang kein anständiger Browser BigInt unterstützt, hab ich das zunächst mit normalen Zahlen implementiert. Und dann nochmal: eratosthenesIteratorFunction-bigint.js.

Welches Script geladen wird, wird per feature detection ermittelt:

<script>
	if (typeof BigInt === 'function')
	{
		document.write('<script src="eratosthenesIteratorFunction-bigint.js"><\/script>');
	}
	else
	{
		document.write('<script src="eratosthenesIteratorFunction.js"><\/script>');
	}
</script>

Ist document.write() an der Stelle OK oder gibt’s da was Besseres?

LLAP 🖖

--
„Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann