Das Ziel ist einfach: Berechnen Sie die Summenfunktion für so viele Zahlen wie möglich in 10 Sekunden und addieren Sie die Zahlen.
Sie müssen Ihr Ergebnis am Ende ausdrucken und es tatsächlich berechnen. Es ist keine automatische Totientenfunktion zulässig, Bignum-Bibliotheken jedoch. Sie müssen bei 1 beginnen und alle ganzen Zahlen nacheinander hochzählen. Sie dürfen keine Nummern überspringen.
Ihre Punktzahl ist, wie viele Zahlen Ihr Programm auf Ihrer Maschine berechnen kann / wie viele mein Programm auf Ihrer Maschine berechnen kann . Mein Code ist ein einfaches Programm in C ++ (Optimierungen aus), hoffentlich können Sie es ausführen.
Wichtige Eigenschaften, die Sie nutzen könnten!
- ob
gcd(m,n) = 1, phi(mn) = phi(m) * phi(n)
- wenn
p
ist prime,phi(p) = p - 1
(fürp < 10^20
) - wenn gerade
n
ist,phi(2n) = 2 phi(n)
- andere im ersten Link aufgeführt
Mein Code
#include <iostream>
using namespace std;
int gcd(int a, int b)
{
while (b != 0)
{
int c = a % b;
a = b;
b = c;
}
return a;
}
int phi(int n)
{
int x = 0;
for (int i=1; i<=n; i++)
{
if (gcd(n, i) == 1)
x++;
}
return x;
}
int main()
{
unsigned int sum = 0;
for (int i=1; i<19000; i++) // Change this so it runs in 10 seconds
{
sum += phi(i);
}
cout << sum << endl;
return 0;
}
fastest-code
qwr
quelle
quelle
1, 3, 5, 2, 4
oder ähnliches?Antworten:
Nimrod: ~ 38.667 (580.000.000 / 15.000)
Diese Antwort verwendet einen ziemlich einfachen Ansatz. Der Code verwendet ein einfaches Primzahlsieb, das die Primzahl der kleinsten Primzahlleistung in jedem Schlitz für zusammengesetzte Zahlen (Null für Primzahlen) speichert, dann die dynamische Programmierung verwendet, um die Totientenfunktion über denselben Bereich zu konstruieren, und dann die Ergebnisse summiert. Das Programm verbringt praktisch die ganze Zeit damit, das Sieb aufzubauen, und berechnet dann die Totientenfunktion in einem Bruchteil der Zeit. Es sieht so aus, als käme es darauf an, ein effizientes Sieb zu konstruieren (mit der leichten Wendung, dass man auch einen Primfaktor für zusammengesetzte Zahlen aus dem Ergebnis extrahieren und die Speichernutzung auf einem vernünftigen Niveau halten muss).
Update: Verbesserte Leistung durch Reduzierung des Speicherbedarfs und Verbesserung des Cache-Verhaltens. Es ist möglich, 5% -10% mehr Leistung zu erzielen, aber die Steigerung der Codekomplexität ist es nicht wert. Letztendlich übt dieser Algorithmus hauptsächlich den von Neumann-Engpass einer CPU aus, und es gibt nur sehr wenige algorithmische Optimierungen, die das umgehen können.
Außerdem wurde der Performance-Teiler aktualisiert, da der C ++ - Code nicht mit allen Optimierungen kompiliert werden sollte und niemand anderes dies tat. :)
Update 2: Optimierter Siebbetrieb für verbesserten Speicherzugriff. Behandeln Sie jetzt kleine Primzahlen in großen Mengen mit memcpy () (~ 5% Beschleunigung) und überspringen Sie beim Sieben größerer Primzahlen ein Vielfaches von 2, 3 und 5 (~ 10% Beschleunigung).
C ++ Code: 9,9 Sekunden (mit g ++ 4.9)
Nimrod Code: 9.9 Sekunden (mit -d: release, gcc 4.9 backend)
quelle
Java, Punktzahl ~ 24.000 (360.000.000 / 15.000)
Der folgende Java-Code berechnet die Totientenfunktion und das Hauptsieb zusammen. Beachten Sie, dass Sie je nach Computer die anfängliche / maximale Heap-Größe erhöhen müssen (auf meinem eher langsamen Laptop musste ich aufsteigen
-Xmx3g -Xms3g
).quelle
Nimrod: ~ 2.333.333 (42.000.000.000 / 18.000)
Dies verwendet einen völlig anderen Ansatz als meine vorherige Antwort. Siehe Kommentare für Details. Das
longint
Modul finden Sie hier .quelle
2*sqrt(n)
), was zu einer viel niedrigeren Punktzahl führt.C #: 49.000 (980.000.000 / 20.000)
/codegolf//a/26800 "Howards Code".
Modifizierte Phi-Werte werden jedoch für ungerade ganze Zahlen berechnet.
Neue Punktzahl: 61.000 (1.220.000.000 / 20.000)
In "App.config" musste "gcAllowVeryLargeObjects enabled = true" hinzugefügt werden.
quelle
Python 3: ~ 24000 (335.000.000 / 14.000)
Meine Version ist eine Python-Portierung von Howards Algorithmus . Meine ursprüngliche Funktion war eine Modifikation eines Algorithmus, der in diesem Blogpost eingeführt wurde .
Ich verwende Numpy- und Numba-Module, um die Ausführungszeit zu beschleunigen. Beachten Sie, dass Sie normalerweise nicht die Typen der lokalen Variablen deklarieren müssen (wenn Sie Numba verwenden), aber in diesem Fall wollte ich die Ausführungszeit so weit wie möglich verkürzen.
Bearbeiten: kombinierte Konstruktsieb- und Zusammenfassungsfunktionen in einer einzigen Funktion.
C ++: 9,99 s (n = 14.000); Python 3: 9.94s (n = 335.000.000)
quelle
Hier ist meine Python-Implementierung, die in der Lage zu sein scheint, ~ 60000 Zahlen in 10 Sekunden zu erzeugen. Ich faktorisiere Zahlen mit dem Pollard-Rho-Algorithmus und dem Rabin-Miller-Primärtest.
quelle
φ (2 n ) = 2 n - 1
Σ φ (2 i ) = 2 i - 1 für i von 1 bis n
Zuerst mal was zu finden:
Für den Referenzcode ist das für mich:
Nun, Haskell:
Es macht etwas mit 2525224 Ziffern in 0,718 Sekunden. Und jetzt merke ich nur den Kommentar von @ Howard.
quelle
Matlab: 1464 = 26355867/18000
Ich kann Ihren Code nicht testen, also habe ich ihn durch 18000 geteilt, da er den schnellsten Computer der getesteten Computer darstellt. Ich kam zu der Partitur mit dieser Eigenschaft:
Mir gefällt vor allem, dass es ein Einzeiler ist:
quelle
phi(p)
allen Nicht-Primzahlenp
?Python 2.7: 10.999 (165975/15090)
Pypy 2.3.1: 28.496 (430000/15090)
Einige interessante Methoden, die ich benutze:
Rabin-Miller Strong Pseudoprime Test - Ein Primalitätstest, der einen effizienten Wahrscheinlichkeitsalgorithmus zur Bestimmung der Primzahl liefert
Eulers Produktformel - Das Produkt befindet sich über den verschiedenen Primzahlen, die n teilen
Code:
quelle