Algorithmus zur Berechnung der Anzahl der Teiler einer bestimmten Anzahl


176

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.


Angesichts Ihrer Anforderungen ist die Anzahl der Faktoren vage. Ich vermute, Sie suchen nach der Anzahl der nicht eindeutigen Primteiler, denn wenn Sie nicht wollten, dass ich codiere, schreiben Sie einfach ein Programm, das immer 1 zurückgibt, wenn die Zahl zum Faktor eins ist, und 2, wenn es etwas anderes ist. 0 könnte eine Änderung brauchen ...
Justin Bozonier

@sker: Gibt es eine Reihe von Werten, für die Sie die Teiler benötigen? Es gibt viele Möglichkeiten, die Faktoren zu berechnen, und jede Methode ist für einen bestimmten Bereich besser geeignet.
Ande Turner

2
Hier ist ein verwandtes interessantes Problem projecteuler.net/problem=12
daniloquio

1
Das naive Sieb von Atkin wird selbst aus dem bearbeiteten Wikipedia-Artikel niemals schneller sein als ein maximal radfaktorisiertes Sieb von Eratosthenes bis zu enormen unpraktischen Grenzen, und die seitensegmentierten Versionen sind sogar noch günstiger für das SoE (siehe SoE primesieve versus SoA primegen as implementiert von Atkins Partner Bernstein. Es ist allgemein falsch, dass ihre Studie SoA schneller bewies, aber sie beschränkten künstlich die Optimierung des SoE, um dies zu beweisen. Weitere Erklärungen finden Sie in meiner SoA-Antwort
GordonBGood

Antworten:


78

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 nlä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.


1
Wenn Sie eine große Zahl berücksichtigen, möchten Sie nicht einmal auf die Primliste schauen müssen . Sie möchten so schnell wie möglich ganze Möglichkeiten ausschalten! Siehe meine Antwort für mehr.
user11318

Mir ist klar, dass dies vor 2 Jahren war, aber Ihre Python-Algo-Verbindung ist unterbrochen. Wissen Sie zufällig, wo sie jetzt existiert?
jb.

2
So n = (a^x * b^y * c^z)-(x + 1) * (y + 1) * (z + 1)ist die Regel
SIslam

1
Wie @Shashank sagt, ist der Algorithmus im Abschnitt "EDIT:" falsch: Angenommen, n = 45 = 3 * 3 * 5. Der größte Primteiler ist 5, aber wenn dieser Wert mit sich selbst multipliziert wird, bis er n überschreitet, meldet der Algorithmus, dass er 2 Kopien des Faktors 5 hat (da 5 * 5 = 25 <45).
j_random_hacker

1
Das 'Sieb von Atkin' hat bestenfalls eine Laufzeitkomplexität von O (N / log (log (N))) . Die Brute-Force-Überprüfung aller möglichen Teiler von 1 ... Sqrt (n) hat eine Laufzeitkomplexität von O (Sqrt (N)), die weit überlegen ist. Wie kommt es, dass diese Antwort akzeptiert wurde?
le_m

47

Es 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 ...)


1
Ihre Technik ist sehr klug, aber sie sagt mir nicht, wie viele Faktoren die Zahl hat, oder?
Sker

23
Sobald Sie die Primfaktorisierung haben, ist es einfach herauszufinden, wie viele Faktoren es gibt. Angenommen, die Primfaktoren sind p1, p2, ..., pk und sie werden m1, m2, ..., mk mal wiederholt. Dann gibt es (1 + m1) (1 + m2) ... (1 + mk) Faktoren.
user11318

Ein interessantes Sieb ist das quadratische Sieb . Dies verwendet die Zahlentheorie - quadratische Kongruenzen und eine lineare Algebra. Ich habe genug gelernt, um es in einem Zahlentheoriekurs im zweiten Jahr an der Universität zu verwenden.
Tanner

33

@ Yasky

Ihre Teilerfunktion hat den Fehler, dass sie für perfekte Quadrate nicht richtig funktioniert.

Versuchen:

int divisors(int x) {
    int limit = x;
    int numberOfDivisors = 0;

    if (x == 1) return 1;

    for (int i = 1; i < limit; ++i) {
        if (x % i == 0) {
            limit = x / i;
            if (limit != i) {
                numberOfDivisors++;
            }
            numberOfDivisors++;
        }
    }

    return numberOfDivisors;
}

6
Verursacht (x% i) keine Division durch Null, wenn i = 0 ist? sollte ich = 1..limit?
Rhu

@rhu Das Überprüfen von 0 ist sowieso sinnlos, da 0 kein Faktor einer beliebigen Zahl ist.
EJoshuaS

29

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:

import operator
# A slightly efficient superset of primes.
def PrimesPlus():
  yield 2
  yield 3
  i = 5
  while True:
    yield i
    if i % 6 == 1:
      i += 2
    i += 2
# Returns a dict d with n = product p ^ d[p]
def GetPrimeDecomp(n):
  d = {}
  primes = PrimesPlus()
  for p in primes:
    while n % p == 0:
      n /= p
      d[p] = d.setdefault(p, 0) + 1
    if n == 1:
      return d
def NumberOfDivisors(n):
  d = GetPrimeDecomp(n)
  powers_plus = map(lambda x: x+1, d.values())
  return reduce(operator.mul, powers_plus, 1)

ps Das ist funktionierender Python-Code, um dieses Problem zu lösen.


11

Hier ist ein direkter O (sqrt (n)) - Algorithmus. Ich habe dies verwendet, um das Projekt Euler zu lösen

def divisors(n):
    count = 2  # accounts for 'n' and '1'
    i = 2
    while i ** 2 < n:
        if n % i == 0:
            count += 2
        i += 1
    if i ** 2 == n:
        count += 1
    return count

aber warum erhöhen Sie die Anzahl immer um 2? ... gibt es einen Satz, den Sie angewendet haben?
SummerCode

3
weil Sie nur bis sqrt (n) fortfahren. Zum Beispiel: Wenn Sie versuchen, alle Teiler für 36 zu finden, zählen Sie von 2 bis 6. Sie wissen, dass 1 & 36,2 & 18, 3 & 12, 4 & 9, 6,6 alle Teiler sind und paarweise vorliegen.
Antony Thomas

2
Vielen Dank Anthony, ich habe jetzt verstanden: D! ein kleiner Nachtrag: Ich denke, es sollte den sqrt (n) -Wert separat behandeln, da es im
Moment

Während O (sqrt (n)) nicht schlecht ist, ist es nicht optimal. Die Berechnung der Primfaktor-Zerlegung kann viel schneller erfolgen und reicht aus, um die Anzahl der Teiler zu berechnen.
le_m

Bei jeder Iteration müssen Sie i² berechnen. Wäre es nicht schneller, i mit √n zu vergleichen (nur einmal berechnet)?
Yukulélé

10

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.


Hier ist ein Link zu einem Pseudocode für ein Problem, das dem sehr ähnlich ist. 2. answers.google.com/answers/threadview/id/392914.html
mR_fr0g

3
Frage 2 hat eine bekannte Lösung. Für eine Faktorisierung von {p_i, k_i}, wobei p_ies sich um einen Primfaktor einer Zahl mit k_iMultiplizitä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.
Will Ness

9

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.


6

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.)

for(int i=1,n=9;((!(n%i)) && printf("%d is a divisor of %d\n",i,n)) || i<=(n/2);i++);//n is your number

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).

int number_of_divisors(int n)
{
    int counter,i;
    for(counter=0,i=1;(!(n%i) && (counter++)) || i<=(n/2);i++);
    return counter;
}

oder wenn Sie eine bestimmte Zahl als Teiler behandeln (arbeiten Sie korrekt für alle Ganzzahlen außer 1 und 2)

int number_of_divisors(int n)
{
    int counter,i;
    for(counter=0,i=1;(!(n%i) && (counter++)) || i<=(n/2);i++);
    return ++counter;
}

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)

int number_of_divisors(int n)
{
    int counter,i;
    for(counter=0,i=1;(!(n%i) && (counter++)) || i<=(n/2);i++);
    if (n==2 || n==1)
    {
    return counter;
    }
    return ++counter;
}

ODER

int number_of_divisors(int n)
{
    int counter,i;
for(counter=0,i=1;(!(i==n) && !(n%i) && (counter++)) || i<=(n/2);i++);
    return ++counter;
}

klein ist schön :)


5

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]:

for z in 1..n:
    prime[z] = false
prime[2] = true;
prime[3] = true;

for x in 1..sqrt(n):
    xx = x * x

    for y in 1..sqrt(n):
        yy = y * y

        z = 4*xx+yy
        if (z <= n) and ((z mod 12 == 1) or (z mod 12 == 5)):
            prime[z] = not prime[z]

        z = z-xx
        if (z <= n) and (z mod 12 == 7):
            prime[z] = not prime[z]

        z = z-yy-yy
        if (z <= n) and (x > y) and (z mod 12 == 11):
            prime[z] = not prime[z]

for z in 5..sqrt(n):
    if prime[z]:
        zz = z*z
        x = zz
        while x <= limit:
            prime[x] = false
            x = x + zz

for z in 2,3,5..n:
    if prime[z]:
        if n modulo z == 0 then print z

5

Sie könnten diesen versuchen. Es ist ein bisschen hackisch, aber es ist ziemlich schnell.

def factors(n):
    for x in xrange(2,n):
        if n%x == 0:
            return (x,) + factors(n/x)
    return (n,1)

2
Während diese Funktion eine Primfaktor-Zerlegung von n in angemessener Zeit liefert, ist sie a) nicht optimal und b) berechnet nicht die Anzahl der Teiler einer gegebenen Zahl gemäß der Frage von OP
le_m

Und wird wegen seiner Rekursion nicht für große Zahlen
funktionieren

Obwohl dies nicht optimal ist und die Faktoren nicht gezählt werden, sondern tatsächlich aufgelistet werden, ist die Einfachheit und Schönheit dieser Faktoren erstaunlich und relativ schnell. ^^
Gaurav Singhal

5

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


3

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.


3

Dies ist eine effiziente Lösung:

#include <iostream>
int main() {
  int num = 20; 
  int numberOfDivisors = 1;

  for (int i = 2; i <= num; i++)
  {
    int exponent = 0;
    while (num % i == 0) {
        exponent++; 
        num /= i;
    }   
    numberOfDivisors *= (exponent+1);
  }

  std::cout << numberOfDivisors << std::endl;
  return 0;
}

2

Teiler machen etwas Spektakuläres: Sie teilen sich vollständig. Wenn Sie die Anzahl der Teiler für eine Zahl überprüfen möchten, nist es eindeutig überflüssig, das gesamte Spektrum abzudecken 1...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.

int divisors (int x) {
    int limit = x;
    int numberOfDivisors = 1;

    for (int i(0); i < limit; ++i) {
        if (x % i == 0) {
            limit = x / i;
            numberOfDivisors++;
        }
    }

    return numberOfDivisors * 2;
}

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.


1
Sie würden eine Division durch 0 bei der ersten Iteration hier haben
Barfoon

Leider nicht. Das ++ i unterscheidet sich von i ++ (was zu einem Fehler beim Teilen durch Null führen würde)
iGbanam

Ich habe Ihre Funktion in PHP geschrieben und ausgeführt - hier ist, was ich habe - i.minus.com/iKzuSXesAkpbp.png
Barfoon

Aus irgendeinem seltsamen Grund funktionierte dies für mich einwandfrei. na ja, mein schlechtes. Start numberOfDivisorsund der Iterator bei 1; Dies sollte die Division durch Null Fehler
beseitigen

1
Ihr Algorithmus funktioniert nicht für perfekte Quadrate. Zum Beispiel gibt es 4 für die Eingabe x = 4 zurück, weil es 2 zweimal zählt ... 1, 2, 2, 4. Die Antwort sollte 3: 1,2,4 sein
Michael

1

Sie möchten das Sieb von Atkin, das hier beschrieben wird: http://en.wikipedia.org/wiki/Sieve_of_Atkin


1
Dadurch erhalten Sie die Primzahlen unter Ihrer angegebenen Anzahl - aber es gibt keine Garantie dafür, dass diese Primzahlen Teiler sein werden? (es sei denn, ich vermisse etwas)
Andrew Edgecombe

Es ist ein kurzer Sprung von hier, um alle Primzahlen <sqrt (N) zu finden, die N gleichmäßig teilen.
SquareCog

1
Es mag ein schneller Sprung sein, aber das Testen aller Primzahlen <sqrt (N) ist immer noch eine schlechte Faktorisierungstechnik, egal wie effizient Sie sie finden. Es gibt viele Möglichkeiten, dies zu verbessern.
user11318

Das Testen der Primzahlen ist O (N). Das Finden der Primzahlen ist der schwierige Teil. Aber selbst mit dem nicht optimierten Eratosthenesieb können Sie alle Primzahlen unter weniger als ein paar Millionen in weniger als einer Sekunde finden. Das deckt jede 64b-Zahl ab, und ich bin sicher, wir reden hier nicht über das Faktorisieren von Krypto-Level-Sachen
Matthew Scharley,

1

Die Primzahlmethode ist hier sehr klar. P [] ist eine Liste von Primzahlen, die kleiner oder gleich sq = sqrt (n) sind;

for (int i = 0 ; i < size && P[i]<=sq ; i++){
          nd = 1;
          while(n%P[i]==0){
               n/=P[i];
               nd++;
               }
          count*=nd;
          if (n==1)break;
          }
      if (n!=1)count*=2;//the confusing line :D :P .

     i will lift the understanding for the reader  .
     i now look forward to a method more optimized  .

1

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

  1. Testen Sie, ob die Zahl eine Primzahl ist (schnell)
  2. Wenn ja, geben Sie 2 zurück
  3. Andernfalls faktorisieren Sie die Zahl (langsam, wenn mehrere große Primfaktoren vorhanden sind)
  4. Berechnen Sie τ (n) aus der Faktorisierung

1

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.

#include<stdio.h>
#include<math.h>
int main()
{
    int i,n,limit,numberOfDivisors=1;
    printf("Enter the number : ");
    scanf("%d",&n);
    limit=(int)sqrt((double)n);
    for(i=2;i<=limit;i++)
        if(n%i==0)
        {
            if(i!=n/i)
                numberOfDivisors+=2;
            else
                numberOfDivisors++;
        }
    printf("%d\n",numberOfDivisors);
    return 0;
}

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.

for(i=2;i*i<=n;i++)
{
    ...
}

1

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.

public static List<Integer> divisors(n) {   
    ArrayList<Integer> aList = new ArrayList();
    int top_count = (int) Math.round(Math.sqrt(n));
    int new_n = n;

    for (int i = 2; i <= top_count; i++) {
        if (new_n == (new_n / i) * i) {
            aList.add(i);
            new_n = new_n / i;
            top_count = (int) Math.round(Math.sqrt(new_n));
            i = 1;
        }
    }
    aList.add(new_n);
    return aList;
}

Ich weiß nicht, was diese Funktion berechnet, aber es ist definitiv nicht die Liste der Teiler von n.
le_m

1

Dies ist die grundlegendste Methode zur Berechnung der Zahlenteiler:

class PrintDivisors
{
    public static void main(String args[])
    {

    System.out.println("Enter the number");

    // Create Scanner object for taking input
    Scanner s=new Scanner(System.in);

    // Read an int
    int n=s.nextInt();

        // Loop from 1 to 'n'
        for(int i=1;i<=n;i++)
        {

            // If remainder is 0 when 'n' is divided by 'i',
            if(n%i==0)
            {
            System.out.print(i+", ");
            }
        }

    // Print [not necessary]    
    System.out.print("are divisors of "+n);

    }
}

1

@ 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.

long long int FindDivisors(long long int n) {
  long long int count = 0;
  long long int i, m = (long long int)sqrt(n);
  for(i = 1;i <= m;i++) {
    if(n % i == 0)
      count += 2;
  }
  if(n / m == m && n % m == 0)
    count--;
  return count;
}

0

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:

factor(N)
    divisor = first_prime
    list_of_factors = { 1 }
    while (N > 1)
        while (N % divisor == 0)
            add divisor to list_of_factors
            N /= divisor
        divisor = next_prime
    return list_of_factors

Es liegt dann an Ihnen, die Faktoren zu kombinieren, um den Rest der Antwort zu bestimmen.


0

Dies ist etwas, das ich basierend auf der Antwort von Justin erfunden habe. Möglicherweise ist eine Optimierung erforderlich.

n=int(input())

a=[]
b=[]

def sieve(n):
    np = n + 1
    s = list(range(np)) 
    s[1] = 0
    sqrtn = int(n**0.5)
    for i in range(2, sqrtn + 1): 
        if s[i]:
            s[i*i: np: i] = [0] * len(range(i*i, np, i))
    return filter(None, s)

k=list(sieve(n))

for i in range(len(k)):
        if n%k[i]==0:
                a.append(k[i])

a.sort()

for i in range(len(a)):
        j=1
        while n%(a[i]**j)==0: 
                j=j+1
        b.append(j-1)

nod=1

for i in range(len(b)):
        nod=nod*(b[i]+1)

print('no.of divisors of {} = {}'.format(n,nod))

0

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

@echo off

modecon:cols=100 lines=100

:start
title Enter the Number to Determine 
cls
echo Determine a number as a product of 2 numbers
echo.
echo Ex1 : C = A * B
echo Ex2 : 8 = 4 * 2
echo.
echo Max Number length is 9
echo.
echo If there is only 1 proces done  it
echo means the number is a prime number
echo.
echo Prime numbers take time to determine
echo Number not prime are determined fast
echo.

set /p number=Enter Number : 
if %number% GTR 999999999 goto start

echo.
set proces=0
set mindet=0
set procent=0
set B=%Number%

:Determining

set /a mindet=%mindet%+1

if %mindet% GTR %B% goto Results

set /a solution=%number% %%% %mindet%

if %solution% NEQ 0 goto Determining
if %solution% EQU 0 set /a proces=%proces%+1

set /a B=%number% / %mindet%

set /a procent=%mindet%*100/%B%

if %procent% EQU 100 set procent=%procent:~0,3%
if %procent% LSS 100 set procent=%procent:~0,2%
if %procent% LSS 10 set procent=%procent:~0,1%

title Progress : %procent% %%%



if %solution% EQU 0 echo %proces%. %mindet% * %B% = %number%
goto Determining

:Results

title %proces% Results Found
echo.
@pause
goto start

882161280 - 1282 Teiler
Dondon

0

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)


0

Versuchen Sie etwas in diese Richtung:

int divisors(int myNum) {
    int limit = myNum;
    int divisorCount = 0;
    if (x == 1) 
        return 1;
    for (int i = 1; i < limit; ++i) {
        if (myNum % i == 0) {
            limit = myNum / i;
            if (limit != i)
                divisorCount++;
            divisorCount++;
        }
    }
    return divisorCount;
}

-1

Ich kenne die effizienteste Methode nicht, aber ich würde Folgendes tun:

  • Erstellen Sie eine Tabelle mit Primzahlen, um alle Primzahlen zu finden, die kleiner oder gleich der Quadratwurzel der Zahl sind (persönlich würde ich das Sieb von Atkin verwenden).
  • Zählen Sie alle Primzahlen, die kleiner oder gleich der Quadratwurzel der Zahl sind, und multiplizieren Sie diese mit zwei. Wenn die Quadratwurzel der Zahl eine Ganzzahl ist, subtrahieren Sie eine von der Zählvariablen.

Sollte funktionieren \ o /

Wenn Sie brauchen, kann ich morgen in C etwas codieren, um es zu demonstrieren.


2
Ich bin verwirrt. Wenn Sie alle Primzahlen kleiner als die Quadratwurzel einer Zahl zählen, erhalten Sie keine Teiler ... Nicht jede Primzahl kleiner als die Quadratwurzel einer Zahl ist ein Teiler für diese Zahl.
Garrett Berg
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.