Jede positive ganze Zahl n ≥ 2 lässt sich als Produkt von Primzahlen darstellen:
Das Ermitteln der Primfaktoren einer Zahl hat zahlreiche Anwendungen. So kann man damit leicht die Anzahl ihrer Teiler bestimmen, ein Gefühl für den größten gemeinsamen Teiler (GCD) und das kleinste gemeinsame Vielfache (LCM) zweier Zahlen bekommen und vieles mehr.
Um eine Zahl n (zum Beispiel 300) in ihre Primfaktoren zu zerlegen, beginnt man mit der kleinsten Primzahl p (2). Ist n durch p teilbar, teilt man so lange durch p, bis das nicht mehr möglich ist (300 / 2 = 150, 150 / 2 = 75).
Nach Abschluss dieser Teilungen erhöht man p um 1 (p = 3) und testet, ob das neue p ein Teiler von n ist. Falls ja, führt man auch hier so lange Divisionen durch, bis n nicht weiter teilbar ist (75 / 3 = 25).
Dann wird p wieder um 1 erhöht (p = 4). Da p selbst nicht mehr prim sein muss, kann es vorkommen, dass n trotzdem nicht durch 4, 6, 8 usw. teilbar ist, wenn alle passenden Primfaktoren bereits ausgeschöpft wurden. Im Beispiel wurde 300 mehrmals durch 2 geteilt, sodass nachher keine Teiler mehr übrig bleiben, die Vielfache von 2 sind. Da man schrittweise vom kleinsten zum größten möglichen Teiler vorgeht, bleiben nur noch echte Primzahlen übrig, die den Rest von n teilen können.
Beim nächsten Schritt erhöht man den Divisor erneut um 1 (p = 5) und wiederholt das Prozedere (75 / 5 = 5, 5 / 5 = 1). Dieser Vorgang läuft, bis der aktuelle Divisor größer ist als . An diesem Punkt ist das, was von n noch übrig bleibt, selbst eine Primzahl, und man kann diesen Wert als letzten Primfaktor zum Ergebnis hinzufügen.
Auf diese Weise erhalten wir für das Beispiel 300 die Zerlegung .
n = ... # Stelle n als Produkt von Primzahlen dar
p, divisors, powers = 1, [], [] # Primfaktor, Teiler und deren Exponenten
while p * p <= n: # solange p <= sqrt(n)
p += 1 # Erhöhe den möglichen Primfaktor p
if n % p != 0: # Falls n nicht durch p teilbar ist, überspringen
continue
divisors.append(p) # n % p == 0 => p ist ein Primfaktor
powers.append(0) # Exponentinitialisierung auf 0
while n % p == 0: # so oft wie möglich teilen
n //= p
powers[-1] += 1 # pro Division den Exponenten um 1 erhöhen
if n > 1: # wenn p > sqrt(n) => n ist selbst ein Primfaktor
divisors.append(n)
powers.append(1)
print(list(zip(divisors, powers))) # Ausgabe der Faktoren zusammen mit ihren Exponenten
In jeder Iteration des Algorithmus wird die Zahl, falls möglich, durch ihren aktuellen Primfaktor geteilt. Der Exponent dieses Faktors wird dabei pro erfolgreicher Division um 1 erhöht.
Schauen wir uns den Ablauf des Algorithmus an ein paar Beispielen an:
n = 24
p = 2, n = 24 (p wurde am Anfang der Schleife von 1 auf 2 erhöht)
n % 2 == 0 ⇒ divisors = [2], powers = [0]n //= 2 ⇒ n = 12, powers = [1]
n //= 2 ⇒ n = 6, powers = [2]n //= 2 ⇒ n = 3, powers = [3]
p = 3, n = 3 ⇒ Abbruch der while-Schleife, denn p * p = 9, was größer als 2 ist
n > 1 ⇒ divisors = [2, 3], powers = [3, 1]
n = 75
p = 2, n = 75
p = 3, n = 75n % 3 == 0 ⇒ divisors = [3], powers = [0]n //= 3 ⇒ n = 25, powers = [1]
p = 4, n = 25
p = 5, n = 25n % 5 == 0 ⇒ divisors = [3, 5], powers = [1, 0]n //= 5 ⇒ n = 5, powers = [1, 1]n //= 5 ⇒ n = 1, powers = [1, 2]
p * p > n ⇒ Abbruch der while-Schleife ⇒ divisors = [3, 5], powers = [1, 2]
n = 84
p = 2, n = 84n % 2 == 0 ⇒ divisors = [2], powers = [0]n //= 2 ⇒ n = 42, powers = [1]n //= 2 ⇒ n = 21, powers = [2]
p = 3, n = 21n % 3 == 0 ⇒ divisors = [2, 3], powers = [2, 0]n //= 3 ⇒ n = 7, powers = [2, 1]
p * p > n ⇒ Abbruch der while-Schleife
n > 1 ⇒ divisors = [2, 3, 7], powers = [2, 1, 1]
n = 31
p = 2, n = 31
p = 3, n = 31
p = 4, n = 31
p = 5, n = 31
p = 6, n = 31
p * p > n ⇒ Abbruch der while-Schleife
n > 1 ⇒ divisors = [31], powers = [1]
Aufgabe
Gegeben ist eine ganze Zahl n. Bestimmen Sie den größten Primfaktor von n.
Eingabe
Die erste Zeile der Eingabe enthält eine einzelne ganze Zahl n (2 ≤ n ≤ ).
Ausgabe
Das Programm soll den größten Primfaktor von n ausgeben.
Beispiele
Eingabe
Ausgabe
8
2
24
3
75
5
31
31
Bonus: Warum prüfen wir nicht nur Primzahlen?
Unsere aktuelle Implementierung des Algorithmus geht alle Zahlen von 2 bis durch. Wäre es nicht sinnvoller, nur Primzahlen in diesem Bereich zu testen?
Auf den ersten Blick klingt das logisch (und in manchen Aufgaben könnte man so vorgehen). Allerdings ist das Bestimmen aller Primzahlen bis (im Worst Case) aufwändiger als einmal einfach alle Zahlen bis durchzugehen und zu prüfen, ob sie Teiler von n sind (genauer gesagt ist das Verfahren zum Ermitteln der Primzahlen bis ). In vielen Fällen braucht die Suche nach allen Primzahlen also mehr Zeit als das direkte Ausprobieren sämtlicher möglicher Kandidaten.
Fällt Ihnen dennoch eine Situation ein, in der es lohnender wäre, zuerst alle Primzahlen zu generieren und dann nur diese zur Primfaktorisierung zu nutzen?