Was wäre der optimalste Algorithmus (in Bezug auf die Leistung), um die Anzahl der Teiler einer bestimmten Anzahl zu berechnen?
Es wäre großartig, wenn Sie einen Pseudocode oder einen Link zu einem Beispiel bereitstellen könnten.
EDIT: Alle Antworten waren sehr hilfreich, danke. Ich implementiere das Sieb von Atkin und werde dann etwas Ähnliches verwenden, wie Jonathan Leffler angegeben hat. Der Link von Justin Bozonier enthält weitere Informationen zu dem, was ich wollte.
Antworten:
Dmitriy hat Recht, dass Sie möchten, dass das Sieb von Atkin die Primliste erstellt, aber ich glaube nicht, dass sich das um das ganze Problem kümmert. Nachdem Sie eine Liste der Primzahlen haben, müssen Sie sehen, wie viele dieser Primzahlen als Teiler fungieren (und wie oft).
Hier ist eine Python für das Algo.Suchen Sie hier und suchen Sie nach "Betreff: Mathematik - Teileralgorithmus benötigen". Zählen Sie einfach die Anzahl der Elemente in der Liste, anstatt sie jedoch zurückzugeben.Hier ist ein Dr. Math , der erklärt, was genau Sie mathematisch tun müssen.
Im Wesentlichen
n
läuft es darauf hinaus, ob Ihre Zahl ist:n = a^x * b^y * c^z
(wobei a, b und c die Hauptteiler von n sind und x, y und z die Häufigkeit sind, mit der der Teiler wiederholt wird), dann ist die Gesamtzahl für alle Teiler:
(x + 1) * (y + 1) * (z + 1)
.Bearbeiten: Übrigens, um a, b, c usw. zu finden, möchten Sie etwas tun, was einem gierigen Algo gleichkommt, wenn ich das richtig verstehe. Beginnen Sie mit Ihrem größten Primteiler und multiplizieren Sie ihn mit sich selbst, bis eine weitere Multiplikation die Zahl n überschreitet. Gehen Sie dann zum nächstniedrigeren Faktor und multiplizieren Sie die vorherige Primzahl mit der aktuellen Primzahl und multiplizieren Sie sie mit der Primzahl, bis die nächste n ... usw. überschreitet. Verfolgen Sie, wie oft Sie die multiplizieren Teiler zusammen und wenden diese Zahlen in die obige Formel an.
Ich bin mir meiner Algo-Beschreibung nicht 100% sicher, aber wenn das nicht so ist, ist es etwas Ähnliches.
quelle
n = (a^x * b^y * c^z)-(x + 1) * (y + 1) * (z + 1)
ist die RegelEs gibt eine Menge mehr Techniken zu Factoring als das Sieb des Atkin. Nehmen wir zum Beispiel an, wir wollen 5893 faktorisieren. Nun, sein Quadrat ist 76,76 ... Jetzt werden wir versuchen, 5893 als Produkt von Quadraten zu schreiben. Nun (77 * 77 - 5893) = 36, was 6 Quadrat ist, also 5893 = 77 * 77 - 6 * 6 = (77 + 6) (77-6) = 83 * 71. Wenn das nicht funktioniert hätte, hätten wir uns angesehen, ob 78 * 78 - 5893 ein perfektes Quadrat ist. Und so weiter. Mit dieser Technik können Sie schnell auf Faktoren nahe der Quadratwurzel von n testen, viel schneller als durch Testen einzelner Primzahlen. Wenn Sie diese Technik kombinieren, um große Primzahlen mit einem Sieb auszuschließen, haben Sie eine viel bessere Faktorisierungsmethode als mit dem Sieb allein.
Und dies ist nur eine von vielen Techniken, die entwickelt wurden. Dies ist ziemlich einfach. Es würde lange dauern, bis Sie beispielsweise genug Zahlentheorie gelernt haben, um die auf elliptischen Kurven basierenden Factoring-Techniken zu verstehen. (Ich weiß, dass sie existieren. Ich verstehe sie nicht.)
Daher würde ich nicht versuchen, dieses Problem selbst zu lösen, es sei denn, Sie haben es mit kleinen ganzen Zahlen zu tun. Stattdessen würde ich versuchen, einen Weg zu finden, etwas wie die PARI- Bibliothek zu verwenden, in der bereits eine hocheffiziente Lösung implementiert ist. Damit kann ich eine zufällige 40-stellige Zahl wie 124321342332143213122323434312213424231341 in etwa 0,05 Sekunden faktorisieren. (Die Faktorisierung, falls Sie sich fragen, ist 29 * 439 * 1321 * 157907 * 284749 * 33843676813 * 4857795469949. Ich bin ziemlich zuversichtlich, dass dies mit dem Sieb von Atkin nicht herausgefunden wurde ...)
quelle
@ Yasky
Ihre Teilerfunktion hat den Fehler, dass sie für perfekte Quadrate nicht richtig funktioniert.
Versuchen:
quelle
Ich bin nicht der Meinung, dass das Sieb von Atkin der richtige Weg ist, da es leicht länger dauern kann, jede Zahl in [1, n] auf Primalität zu überprüfen, als die Zahl nach Divisionen zu reduzieren.
Hier ist ein Code, der zwar etwas hackiger ist, aber im Allgemeinen viel schneller:
ps Das ist funktionierender Python-Code, um dieses Problem zu lösen.
quelle
Hier ist ein direkter O (sqrt (n)) - Algorithmus. Ich habe dies verwendet, um das Projekt Euler zu lösen
quelle
Diese interessante Frage ist viel schwieriger als es aussieht und wurde nicht beantwortet. Die Frage kann in 2 sehr unterschiedliche Fragen zerlegt werden.
1 bei gegebenem N finden Sie die Liste L der Primfaktoren von N.
2 Bei gegebenem L berechnen Sie die Anzahl der eindeutigen Kombinationen
Alle Antworten, die ich bisher sehe, beziehen sich auf Nummer 1 und erwähnen nicht, dass sie für enorme Zahlen nicht nachvollziehbar sind. Für mittelgroße N, sogar 64-Bit-Zahlen, ist es einfach; für enorme N kann das Factoring-Problem "für immer" dauern. Die Verschlüsselung mit öffentlichen Schlüsseln hängt davon ab.
Frage 2 braucht mehr Diskussion. Wenn L nur eindeutige Zahlen enthält, ist dies eine einfache Berechnung unter Verwendung der Kombinationsformel zur Auswahl von k Objekten aus n Elementen. Tatsächlich müssen Sie die Ergebnisse der Anwendung der Formel summieren, während Sie k von 1 bis sizeof (L) variieren. L enthält jedoch normalerweise mehrere Vorkommen mehrerer Primzahlen. Zum Beispiel ist L = {2,2,2,3,3,5} die Faktorisierung von N = 360. Jetzt ist dieses Problem ziemlich schwierig!
Wiederholen Sie Nr. 2, wenn Sammlung C k Elemente enthält, so dass Element a Duplikate und Element b Duplikate usw. enthält. Wie viele eindeutige Kombinationen von 1 bis k-1 Elementen gibt es? Zum Beispiel müssen {2}, {2,2}, {2,2,2}, {2,3}, {2,2,3,3} jeweils einmal und nur einmal vorkommen, wenn L = {2,2 2,3,3,5}. Jede solche eindeutige Untersammlung ist ein eindeutiger Teiler von N, indem die Elemente in der Untersammlung multipliziert werden.
quelle
p_i
es sich um einen Primfaktor einer Zahl mitk_i
Multiplizität handelt, beträgt die Gesamtzahl der Teiler dieser Zahl(k_1+1)*(k_2+1)*...*(k_n+1)
. Ich denke, Sie wissen das inzwischen, aber ich schreibe es auf, wenn ein zufälliger Leser hier ist.Eine Antwort auf Ihre Frage hängt stark von der Größe der Ganzzahl ab. Methoden für kleine Zahlen, z. B. weniger als 100 Bit, und für Zahlen ~ 1000 Bit (wie sie in der Kryptographie verwendet werden) sind völlig unterschiedlich.
Allgemeiner Überblick: http://en.wikipedia.org/wiki/Divisor_function
Werte für kleine
n
und einige nützliche Referenzen: A000005: d (n) (auch tau (n) oder sigma_0 (n) genannt), die Anzahl der Teiler von n.Beispiel aus der Praxis : Faktorisierung von ganzen Zahlen
quelle
NUR eine Zeile
Ich habe sehr sorgfältig über Ihre Frage nachgedacht und versucht, einen hocheffizienten und performanten Code zu schreiben. Um alle Teiler einer bestimmten Zahl auf dem Bildschirm zu drucken, benötigen wir nur eine Codezeile! (Verwenden Sie beim Kompilieren über gcc die Option -std = c99.)
Um die Anzahl der Teiler zu ermitteln, können Sie die folgende sehr sehr schnelle Funktion verwenden (arbeiten Sie korrekt für alle Ganzzahlen außer 1 und 2).
oder wenn Sie eine bestimmte Zahl als Teiler behandeln (arbeiten Sie korrekt für alle Ganzzahlen außer 1 und 2)
HINWEIS: Zwei der oben genannten Funktionen funktionieren ordnungsgemäß für alle positiven Ganzzahlen mit Ausnahme von Nummer 1 und 2, sodass sie für alle Zahlen größer als 2 funktionieren. Wenn Sie jedoch 1 und 2 abdecken müssen, können Sie eine der folgenden Funktionen verwenden (ein wenig) Langsamer)
ODER
klein ist schön :)
quelle
Das Sieb von Atkin ist eine optimierte Version des Siebs von Eratosthenes, die alle Primzahlen bis zu einer bestimmten Ganzzahl angibt. Sie sollten in der Lage sein, dies für weitere Details zu googeln.
Sobald Sie diese Liste haben, ist es einfach, Ihre Zahl durch jede Primzahl zu teilen, um festzustellen, ob es sich um einen exakten Teiler handelt (dh der Rest ist Null).
Die grundlegenden Schritte zur Berechnung der Teiler für eine Zahl (n) sind [dies ist ein Pseudocode, der aus echtem Code konvertiert wurde, also hoffe ich, dass ich keine Fehler eingeführt habe]:
quelle
Sie könnten diesen versuchen. Es ist ein bisschen hackisch, aber es ist ziemlich schnell.
quelle
Sobald Sie die Primfaktorisierung haben, gibt es eine Möglichkeit, die Anzahl der Teiler zu ermitteln. Addiere einen zu jedem der Exponenten für jeden einzelnen Faktor und multipliziere dann die Exponenten miteinander.
Zum Beispiel: 36 Primfaktorisierung: 2 ^ 2 * 3 ^ 2 Teiler: 1, 2, 3, 4, 6, 9, 12, 18, 36 Anzahl der Teiler: 9
Addiere eins zu jedem Exponenten 2 ^ 3 * 3 ^ 3 Multipliziere Exponenten: 3 * 3 = 9
quelle
Bevor Sie sich zu einer Lösung verpflichten, sollten Sie bedenken, dass der Sieve-Ansatz im typischen Fall möglicherweise keine gute Antwort ist.
Vor einiger Zeit gab es eine Hauptfrage, und ich habe einen Zeittest durchgeführt - für 32-Bit-Ganzzahlen war zumindest die Bestimmung, ob es sich um eine Primzahl handelte, langsamer als Brute Force. Es gibt zwei Faktoren:
1) Während ein Mensch eine Weile braucht, um eine Teilung durchzuführen, ist er am Computer sehr schnell - ähnlich wie die Kosten für das Nachschlagen der Antwort.
2) Wenn Sie keine Primärtabelle haben, können Sie eine Schleife erstellen, die vollständig im L1-Cache ausgeführt wird. Das macht es schneller.
quelle
Dies ist eine effiziente Lösung:
quelle
Teiler machen etwas Spektakuläres: Sie teilen sich vollständig. Wenn Sie die Anzahl der Teiler für eine Zahl überprüfen möchten,
n
ist es eindeutig überflüssig, das gesamte Spektrum abzudecken1...n
. Ich habe keine eingehenden Nachforschungen angestellt, aber das Problem 12 von Project Euler zu Dreieckszahlen gelöst . Meine Lösung für den Test mit mehr als 500 Teilern lief 309504 Mikrosekunden (~ 0,3 s). Ich habe diese Divisor-Funktion für die Lösung geschrieben.Zu jedem Algorithmus gibt es eine Schwachstelle. Ich dachte, das sei schwach gegen Primzahlen. Da jedoch dreieckige Zahlen nicht gedruckt werden, hat es seinen Zweck einwandfrei erfüllt. Aufgrund meiner Profilerstellung denke ich, dass es ziemlich gut funktioniert hat.
Schöne Ferien.
quelle
numberOfDivisors
und der Iterator bei 1; Dies sollte die Division durch Null FehlerSie möchten das Sieb von Atkin, das hier beschrieben wird: http://en.wikipedia.org/wiki/Sieve_of_Atkin
quelle
Die Primzahlmethode ist hier sehr klar. P [] ist eine Liste von Primzahlen, die kleiner oder gleich sq = sqrt (n) sind;
quelle
Zahlentheoretische Lehrbücher nennen die Divisor-Zählfunktion tau. Die erste interessante Tatsache ist, dass es multiplikativ ist, dh. τ (ab) = τ (a) τ (b), wenn a und b keinen gemeinsamen Faktor haben. (Beweis: Jedes Teilerpaar von a und b ergibt einen eigenen Teiler von ab).
Man beachte nun, dass für pa prime τ (p ** k) = k + 1 (die Potenzen von p) ist. Somit können Sie τ (n) leicht aus seiner Faktorisierung berechnen.
Das Faktorisieren großer Zahlen kann jedoch langsam sein (die Sicherheit der RSA-Krytopraphie hängt davon ab, dass das Produkt zweier großer Primzahlen schwer zu faktorisieren ist). Dies legt diesen optimierten Algorithmus nahe
quelle
Das folgende C-Programm ermittelt die Anzahl der Teiler einer bestimmten Anzahl.
Die Komplexität des obigen Algorithmus ist O (sqrt (n)).
Dieser Algorithmus funktioniert korrekt für die Zahlen, die ein perfektes Quadrat sind, sowie für die Zahlen, die kein perfektes Quadrat sind.
Beachten Sie, dass das obere Limit der Schleife auf die Quadratwurzel der Zahl gesetzt wird, um den Algorithmus am effizientesten zu erhalten.
Beachten Sie, dass das Speichern des oberen Grenzwerts in einer separaten Variablen auch Zeit spart. Sie sollten die Funktion sqrt nicht im Bedingungsabschnitt der for-Schleife aufrufen. Dies spart auch Rechenzeit.
Anstelle der obigen for-Schleife können Sie auch die folgende Schleife verwenden, die noch effizienter ist, da die Quadratwurzel der Zahl nicht mehr gefunden werden muss.
quelle
Hier ist eine Funktion, die ich geschrieben habe. Die schlechteste Zeitkomplexität ist O (sqrt (n)), die beste Zeit dagegen ist O (log (n)). Es gibt Ihnen alle Hauptteiler zusammen mit der Anzahl seiner Vorkommen.
quelle
Dies ist die grundlegendste Methode zur Berechnung der Zahlenteiler:
quelle
@ Kendall
Ich habe Ihren Code getestet und einige Verbesserungen vorgenommen, jetzt ist er noch schneller. Ich habe auch mit @ هومن جاویدپور Code getestet, dies ist auch schneller als sein Code.
quelle
Ist das nicht nur eine Frage der Faktorisierung der Zahl - der Bestimmung aller Faktoren der Zahl? Sie können dann entscheiden, ob Sie alle Kombinationen eines oder mehrerer Faktoren benötigen.
Ein möglicher Algorithmus wäre also:
Es liegt dann an Ihnen, die Faktoren zu kombinieren, um den Rest der Antwort zu bestimmen.
quelle
Dies ist etwas, das ich basierend auf der Antwort von Justin erfunden habe. Möglicherweise ist eine Optimierung erforderlich.
quelle
Ich denke, das ist, wonach Sie suchen. Ich mache genau das, wonach Sie gefragt haben. Kopieren Sie es und fügen Sie es in Notepad ein. Speichern Sie es als * .bat.Run.Enter Number. Multiplizieren Sie den Prozess mit 2 und das ist die Anzahl der Teiler. Ich habe das absichtlich gemacht, damit es die Teiler schneller bestimmt:
Bitte beachten Sie, dass ein CMD-Wagen Werte über 999999999 nicht unterstützen kann
quelle
Ich denke, dieser wird sowohl praktisch als auch präzise sein
script.pyton
>>>factors=[ x for x in range (1,n+1) if n%x==0] print len(factors)
quelle
Versuchen Sie etwas in diese Richtung:
quelle
Ich kenne die effizienteste Methode nicht, aber ich würde Folgendes tun:
Sollte funktionieren \ o /
Wenn Sie brauchen, kann ich morgen in C etwas codieren, um es zu demonstrieren.
quelle