App installieren
How to install the app on iOS
Follow along with the video below to see how to install our site as a web app on your home screen.
Anmerkung: This feature may not be available in some browsers.
Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden.
Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Programmierwettbewerb: Primzahlzerlegung
- Ersteller i_hasser
- Erstellt am
Hi
Ziel ist es für eine sehr große Zahl möglichst schnell alle Darstellungsmöglichkeiten durch a*b zu finden, wo bei a und b eine Primzahl sein muss.
Also zb. 21=3*7
Solche Zerlegungen spielen zb. beim Knacken von Verschlüsselungen eine wichtige Rolle.
Sprachen usw. sind alle erlaubt, sagen wir außer reinem Assembler (inline Assembler ist natürlich auch erlaubt). Betriebssysteme geht auch alles, aber ich denk es wäre erstmal besser wir bleiben bei x86 (-16, -32 und -64 ). Lösungen auf anderen Architekturen sind natürlich auch willkommen.
Und damit wir nicht in das Dilemma mit Zahlenlibs kommen denk ich beschränken wir das erstmal auf ausgewählte 64bit Integer und sehen wie die Zeiten dafür aussehen. Zum Testen gibts hier eine Liste mit gültigen Zahlen (die sich auch tatsächlich in a*b für Primzahlen zerlegen lassen):
21
(kommt noch mehr )
Viel Spaß!
Ziel ist es für eine sehr große Zahl möglichst schnell alle Darstellungsmöglichkeiten durch a*b zu finden, wo bei a und b eine Primzahl sein muss.
Also zb. 21=3*7
Solche Zerlegungen spielen zb. beim Knacken von Verschlüsselungen eine wichtige Rolle.
Sprachen usw. sind alle erlaubt, sagen wir außer reinem Assembler (inline Assembler ist natürlich auch erlaubt). Betriebssysteme geht auch alles, aber ich denk es wäre erstmal besser wir bleiben bei x86 (-16, -32 und -64 ). Lösungen auf anderen Architekturen sind natürlich auch willkommen.
Und damit wir nicht in das Dilemma mit Zahlenlibs kommen denk ich beschränken wir das erstmal auf ausgewählte 64bit Integer und sehen wie die Zeiten dafür aussehen. Zum Testen gibts hier eine Liste mit gültigen Zahlen (die sich auch tatsächlich in a*b für Primzahlen zerlegen lassen):
21
(kommt noch mehr )
Viel Spaß!
mj
Technische Administration, Dinosaurier, ,
- Mitglied seit
- 17.10.2000
- Beiträge
- 19.529
- Renomée
- 272
- Standort
- Austin, TX
- Mein Laptop
- 2,4kg schwer
- Prozessor
- eckig... glaub ich
- Mainboard
- quadratisch, praktisch, gut
- Kühlung
- kühler?
- Speicher
- ja
- Grafikprozessor
- auch
- Display
- viel bunt
- HDD
- ist drin
- Optisches Laufwerk
- ist auch drin (irgendwo)
- Soundkarte
- tut manchmal tuuut
- Gehäuse
- mit aufkleber!
- Netzteil
- so mit kabel und so... voll toll
- Betriebssystem
- das eine da das wo dingenskirchen halt, nech?
- Webbrowser
- so ein teil da... so grün und so
- Verschiedenes
- nunu!
So, ich liefere gleich mal den ersten Beitrag, erstmal unkommentiert. Die Kommentare mach ich grade, wer es also noch nicht versteht, etwas Geduld bitte
Prim.java
Start.java
Das Prinzip dahinter ist ganz simpel: Es wird zunächst ein Feld erzeugt mit allen Primzahlen zw. 0 und 400. Dies ist variabel, so dass diese Lösung grundsätzlich auch für größere Zahlen geeignet ist.
Anschließend wird die gegebene Zahl (in unserem Fall 21) der Reihe nach, von der kleinsten Zahl beginnend durch jede Zahl die in dem Feld gespeichert ist geteilt und festgestellt, ob das Ergebnis auch eine Primzahl ist. Ist dem der Fall, dann haben wir das Ergebnis - fertig.
Edit: So, mittlerweile hab ich auch die Kommentare hinzugefügt, mehr gibt's da eigentlich nicht zu sagen. Für kleine Zahlen ist diese Lösung sehr schnell, mal sehen was ich ändern muss wenn größere Zahlen ins Spiel kommen. Natürlich ist diese Lösung as-is höchstens für Zahlen des Datentyps long zulässig.
Prim.java
Start.java
Das Prinzip dahinter ist ganz simpel: Es wird zunächst ein Feld erzeugt mit allen Primzahlen zw. 0 und 400. Dies ist variabel, so dass diese Lösung grundsätzlich auch für größere Zahlen geeignet ist.
Anschließend wird die gegebene Zahl (in unserem Fall 21) der Reihe nach, von der kleinsten Zahl beginnend durch jede Zahl die in dem Feld gespeichert ist geteilt und festgestellt, ob das Ergebnis auch eine Primzahl ist. Ist dem der Fall, dann haben wir das Ergebnis - fertig.
Edit: So, mittlerweile hab ich auch die Kommentare hinzugefügt, mehr gibt's da eigentlich nicht zu sagen. Für kleine Zahlen ist diese Lösung sehr schnell, mal sehen was ich ändern muss wenn größere Zahlen ins Spiel kommen. Natürlich ist diese Lösung as-is höchstens für Zahlen des Datentyps long zulässig.
JKuehl
Grand Admiral Special
- Mitglied seit
- 22.06.2003
- Beiträge
- 7.903
- Renomée
- 145
- Standort
- Stockholm, Schweden
- Mitglied der Planet 3DNow! Kavallerie!
- Aktuelle Projekte
- POEM, SIMAP
- Lieblingsprojekt
- SIMAP, POEM
- Meine Systeme
- Q6600
- BOINC-Statistiken
- Folding@Home-Statistiken
- Prozessor
- Ryzen-3700x
- Mainboard
- Asus B350 Prime Plus
- Kühlung
- Fractal Design Celsius 240
- Speicher
- 48 GB Corsair LPX 3000
- Grafikprozessor
- 1080ti
- Display
- 28" Samsung 3840x2160
- SSD
- Samsung Evo 960 500Gb
- Soundkarte
- Creative X-Fi Titanium PCIe
- Netzteil
- Be Quiet Dark Power 650
- Betriebssystem
- Windows 10 64 Bit
ich werde die tage mal probieren unseren lenstra mit elliptischen kurven algo von maple auf c zu porten.
evtl vorher auch die pollard p-1 methode, weil die wesentliche einfacher zu implementieren ist.
evtl vorher auch die pollard p-1 methode, weil die wesentliche einfacher zu implementieren ist.
mj
Technische Administration, Dinosaurier, ,
- Mitglied seit
- 17.10.2000
- Beiträge
- 19.529
- Renomée
- 272
- Standort
- Austin, TX
- Mein Laptop
- 2,4kg schwer
- Prozessor
- eckig... glaub ich
- Mainboard
- quadratisch, praktisch, gut
- Kühlung
- kühler?
- Speicher
- ja
- Grafikprozessor
- auch
- Display
- viel bunt
- HDD
- ist drin
- Optisches Laufwerk
- ist auch drin (irgendwo)
- Soundkarte
- tut manchmal tuuut
- Gehäuse
- mit aufkleber!
- Netzteil
- so mit kabel und so... voll toll
- Betriebssystem
- das eine da das wo dingenskirchen halt, nech?
- Webbrowser
- so ein teil da... so grün und so
- Verschiedenes
- nunu!
Ich denk, ich werd mich heut Abend mal dran machen, das Sieb des Eratosthenes in Java implementieren. Das sollte die Erstellung des Arrays mit Primzahlen stark beschleunigen und auch für größere Zahlen fitmachen
@[ab]noname:
Dein Code compiliert nicht.
@[ab]noname:
Dein Code compiliert nicht.
mj
Technische Administration, Dinosaurier, ,
- Mitglied seit
- 17.10.2000
- Beiträge
- 19.529
- Renomée
- 272
- Standort
- Austin, TX
- Mein Laptop
- 2,4kg schwer
- Prozessor
- eckig... glaub ich
- Mainboard
- quadratisch, praktisch, gut
- Kühlung
- kühler?
- Speicher
- ja
- Grafikprozessor
- auch
- Display
- viel bunt
- HDD
- ist drin
- Optisches Laufwerk
- ist auch drin (irgendwo)
- Soundkarte
- tut manchmal tuuut
- Gehäuse
- mit aufkleber!
- Netzteil
- so mit kabel und so... voll toll
- Betriebssystem
- das eine da das wo dingenskirchen halt, nech?
- Webbrowser
- so ein teil da... so grün und so
- Verschiedenes
- nunu!
Compiler gcc 2.95.4 unter Debian Linux. Funktioniert im übrigen auch nicht, wenn ich __int64 durch long ersetzt im typedef. Die genaue Fehlermeldung:
martin@debian:~/sw$ g++ prime.cpp -o prime
prime.cpp: In function `void Search2PrimFacts(long int)':
prime.cpp:23: implicit declaration of function `int printf(...)'
Ich installiere grade gcc-3.3, mal sehen ob's damit geht.
martin@debian:~/sw$ g++ prime.cpp -o prime
prime.cpp: In function `void Search2PrimFacts(long int)':
prime.cpp:23: implicit declaration of function `int printf(...)'
Ich installiere grade gcc-3.3, mal sehen ob's damit geht.
mj
Technische Administration, Dinosaurier, ,
- Mitglied seit
- 17.10.2000
- Beiträge
- 19.529
- Renomée
- 272
- Standort
- Austin, TX
- Mein Laptop
- 2,4kg schwer
- Prozessor
- eckig... glaub ich
- Mainboard
- quadratisch, praktisch, gut
- Kühlung
- kühler?
- Speicher
- ja
- Grafikprozessor
- auch
- Display
- viel bunt
- HDD
- ist drin
- Optisches Laufwerk
- ist auch drin (irgendwo)
- Soundkarte
- tut manchmal tuuut
- Gehäuse
- mit aufkleber!
- Netzteil
- so mit kabel und so... voll toll
- Betriebssystem
- das eine da das wo dingenskirchen halt, nech?
- Webbrowser
- so ein teil da... so grün und so
- Verschiedenes
- nunu!
Nope, auch ein
#include <cstdlib>
hilft nicht, gleicher Fehler.
#include <cstdlib>
hilft nicht, gleicher Fehler.
mj
Technische Administration, Dinosaurier, ,
- Mitglied seit
- 17.10.2000
- Beiträge
- 19.529
- Renomée
- 272
- Standort
- Austin, TX
- Mein Laptop
- 2,4kg schwer
- Prozessor
- eckig... glaub ich
- Mainboard
- quadratisch, praktisch, gut
- Kühlung
- kühler?
- Speicher
- ja
- Grafikprozessor
- auch
- Display
- viel bunt
- HDD
- ist drin
- Optisches Laufwerk
- ist auch drin (irgendwo)
- Soundkarte
- tut manchmal tuuut
- Gehäuse
- mit aufkleber!
- Netzteil
- so mit kabel und so... voll toll
- Betriebssystem
- das eine da das wo dingenskirchen halt, nech?
- Webbrowser
- so ein teil da... so grün und so
- Verschiedenes
- nunu!
So, jetzt hab ich das ganze mittels BigInteger implementiert. Sieht jetzt zwar deutlich leichter und strukturierter aus, ist aber langsamer. Das liegt nicht nur daran, dass
Java's BigInteger relativ lahm ist (Strukturbedingt) sondern auch daran, dass eine Implementierung eines Primzahlsiebs nicht nur unnötig kompliziert, sondern auch unnötig geworden ist.
Der Quellcode kann hier gefunden werden, derzeit läuft grade ein Testlauf auf einem Pentium 4 / 1.8 GHz und Debian Linux mit der kleinsten der von JKuehl geposteten Zahlen.
Edit: HAHA! Im Moment in dem ich es schreibe, bringt er auch schon ein Ergebnis, ich werd jetzt auch mal die anderen Zahlen durchlaufen lassen. An der nächstgrößeren Zahl rechnet er jetzt schon eine Ewigkeit rum...
Ergebnisse Intel Pentium4 (1.8 GHz):
outdated, siehe unten
Ergebnisse AMD Opteron 144 (1.8 GHz):
outdated, siehe unten
Java's BigInteger relativ lahm ist (Strukturbedingt) sondern auch daran, dass eine Implementierung eines Primzahlsiebs nicht nur unnötig kompliziert, sondern auch unnötig geworden ist.
Der Quellcode kann hier gefunden werden, derzeit läuft grade ein Testlauf auf einem Pentium 4 / 1.8 GHz und Debian Linux mit der kleinsten der von JKuehl geposteten Zahlen.
Edit: HAHA! Im Moment in dem ich es schreibe, bringt er auch schon ein Ergebnis, ich werd jetzt auch mal die anderen Zahlen durchlaufen lassen. An der nächstgrößeren Zahl rechnet er jetzt schon eine Ewigkeit rum...
Ergebnisse Intel Pentium4 (1.8 GHz):
outdated, siehe unten
Ergebnisse AMD Opteron 144 (1.8 GHz):
outdated, siehe unten
mj
Technische Administration, Dinosaurier, ,
- Mitglied seit
- 17.10.2000
- Beiträge
- 19.529
- Renomée
- 272
- Standort
- Austin, TX
- Mein Laptop
- 2,4kg schwer
- Prozessor
- eckig... glaub ich
- Mainboard
- quadratisch, praktisch, gut
- Kühlung
- kühler?
- Speicher
- ja
- Grafikprozessor
- auch
- Display
- viel bunt
- HDD
- ist drin
- Optisches Laufwerk
- ist auch drin (irgendwo)
- Soundkarte
- tut manchmal tuuut
- Gehäuse
- mit aufkleber!
- Netzteil
- so mit kabel und so... voll toll
- Betriebssystem
- das eine da das wo dingenskirchen halt, nech?
- Webbrowser
- so ein teil da... so grün und so
- Verschiedenes
- nunu!
Hmm... der zweite Durchlauf läuft immer noch, mittlerweile schon gut über 40 Minuten
Ich glaub, da ist noch einiges an Optimierungsarbeit zu leisten. Werd's trotzdem mal über Nacht auf'm Opteron laufen lassen, allerdings nicht die zweitkleinste sondern gleich die größte der von JKuehl genannten Zahlen
Edit:
HOLY F***
Vergesst die Ergebnisse oben, durch minimales Optimieren bin ich jetzt auf folgendes Ergebnis gekommen (gemessen auf einem AMD Opteron 144 (1.8 GHz) mit 1024MB DDR333 Speicher unter Debian Linux, Java 1.4.2):
1949565409282837: 0m6.785s
312133288776418481: 2m11.723s
11081452861688528621: 20m48.564s
Der optimierte Quellcode findet sich hier. Und für diejenigen, die Probleme habe das ganze mit javac zu compilieren, hab ich auch gleich noch die .class Dateien beigefügt.
Ich glaub, da ist noch einiges an Optimierungsarbeit zu leisten. Werd's trotzdem mal über Nacht auf'm Opteron laufen lassen, allerdings nicht die zweitkleinste sondern gleich die größte der von JKuehl genannten Zahlen
Edit:
HOLY F***
Vergesst die Ergebnisse oben, durch minimales Optimieren bin ich jetzt auf folgendes Ergebnis gekommen (gemessen auf einem AMD Opteron 144 (1.8 GHz) mit 1024MB DDR333 Speicher unter Debian Linux, Java 1.4.2):
1949565409282837: 0m6.785s
312133288776418481: 2m11.723s
11081452861688528621: 20m48.564s
Der optimierte Quellcode findet sich hier. Und für diejenigen, die Probleme habe das ganze mit javac zu compilieren, hab ich auch gleich noch die .class Dateien beigefügt.
BoMbY
Grand Admiral Special
- Mitglied seit
- 22.11.2001
- Beiträge
- 7.468
- Renomée
- 293
- Standort
- Aachen
- Prozessor
- Ryzen 3700X
- Mainboard
- Gigabyte X570 Aorus Elite
- Kühlung
- Noctua NH-U12A
- Speicher
- 2x16 GB, G.Skill F4-3200C14D-32GVK @ 3600 16-16-16-32-48-1T
- Grafikprozessor
- RX 5700 XTX
- Display
- Samsung CHG70, 32", 2560x1440@144Hz, FreeSync2
- SSD
- AORUS NVMe Gen4 SSD 2TB, Samsung 960 EVO 1TB, Samsung 840 EVO 1TB, Samsung 850 EVO 512GB
- Optisches Laufwerk
- Sony BD-5300S-0B (eSATA)
- Gehäuse
- Phanteks Evolv ATX
- Netzteil
- Enermax Platimax D.F. 750W
- Betriebssystem
- Windows 10
- Webbrowser
- Firefox
Tagchen,
wo ich gerade das hier sehe:
Ihr braucht übrigens nur soviel hier zu testen:
weil mathematisch beweisbar:
heißt im Prinzip, einer der beiden Primfaktoren ist auf jedenfall kleiner als die Wurzel des Produkts.
Ich würde also sowas machen (für max. zwei Primfaktoren):
m.f.g.
BoMbY
wo ich gerade das hier sehe:
for(i64 i = 3; i <= Number; i += 2)
Ihr braucht übrigens nur soviel hier zu testen:
for(i64 i = 3; i <= sqrt(Number); i += 2)
weil mathematisch beweisbar:
sqrt(pq) > p oder sqrt(pq) > q
heißt im Prinzip, einer der beiden Primfaktoren ist auf jedenfall kleiner als die Wurzel des Produkts.
Ich würde also sowas machen (für max. zwei Primfaktoren):
Code:
void Search2PrimFacts(i64 Number) {
i64 i = 3; // naja, die zwei ist ja fast wirklich egal
bool found = false;
while ( i <= round(sqrt(Number)) && !found)
{
if (isPrime(i))
{
if (Number % i == 0)
{
printf("%I64d*%I64d=%i64d\n", i, Number / i, Number);
found = true;
}
}
i += 2;
}
}
m.f.g.
BoMbY
Zuletzt bearbeitet:
BoMbY
Grand Admiral Special
- Mitglied seit
- 22.11.2001
- Beiträge
- 7.468
- Renomée
- 293
- Standort
- Aachen
- Prozessor
- Ryzen 3700X
- Mainboard
- Gigabyte X570 Aorus Elite
- Kühlung
- Noctua NH-U12A
- Speicher
- 2x16 GB, G.Skill F4-3200C14D-32GVK @ 3600 16-16-16-32-48-1T
- Grafikprozessor
- RX 5700 XTX
- Display
- Samsung CHG70, 32", 2560x1440@144Hz, FreeSync2
- SSD
- AORUS NVMe Gen4 SSD 2TB, Samsung 960 EVO 1TB, Samsung 840 EVO 1TB, Samsung 850 EVO 512GB
- Optisches Laufwerk
- Sony BD-5300S-0B (eSATA)
- Gehäuse
- Phanteks Evolv ATX
- Netzteil
- Enermax Platimax D.F. 750W
- Betriebssystem
- Windows 10
- Webbrowser
- Firefox
Wobei ich gerade Überlege: Ist die statistische Wahrscheinlichkeit nicht höher das die Gesuchte Primzahl p irgendwo zwischen sqrt(pq)/2 und sqrt(pq) liegt, als zwischen 3 und sqrt(pq)/2? Wenn dem so ist würde ich nicht von 3 hochzählen sondern von sqrt(pq) runter. Wobei, je höher die getestete Zahl, desto länger dauert es ja auch das Modulo zu berechnen...
Das müsste ich mal genau ausrechnen/testen.
m.f.g.
BoMbY
Das müsste ich mal genau ausrechnen/testen.
m.f.g.
BoMbY
BoMbY
Grand Admiral Special
- Mitglied seit
- 22.11.2001
- Beiträge
- 7.468
- Renomée
- 293
- Standort
- Aachen
- Prozessor
- Ryzen 3700X
- Mainboard
- Gigabyte X570 Aorus Elite
- Kühlung
- Noctua NH-U12A
- Speicher
- 2x16 GB, G.Skill F4-3200C14D-32GVK @ 3600 16-16-16-32-48-1T
- Grafikprozessor
- RX 5700 XTX
- Display
- Samsung CHG70, 32", 2560x1440@144Hz, FreeSync2
- SSD
- AORUS NVMe Gen4 SSD 2TB, Samsung 960 EVO 1TB, Samsung 840 EVO 1TB, Samsung 850 EVO 512GB
- Optisches Laufwerk
- Sony BD-5300S-0B (eSATA)
- Gehäuse
- Phanteks Evolv ATX
- Netzteil
- Enermax Platimax D.F. 750W
- Betriebssystem
- Windows 10
- Webbrowser
- Firefox
Also wenn ich nicht ganz dumm bin, ist das hier der Beweis (V=oder):
Annahme: sqrt(pq) > p V sqrt(pq) > q
Zwischenschritt: pq > p² V pq > q²
Schluss: q > p V p > q
Sprich also q ist größer p oder p ist größer als q <- und davon können wir ja wohl ausgehen, oder? Okay, ich war jetzt zu faul den Fall (gleich =) zu berücksichtigen, aber der wird auch abgedeckt.
m.f.g.
BoMbY
Edit: PS: Klar, das ist nicht schneller wenn man einen Primfaktor findet, nur wenn man keinen findet!
Annahme: sqrt(pq) > p V sqrt(pq) > q
Zwischenschritt: pq > p² V pq > q²
Schluss: q > p V p > q
Sprich also q ist größer p oder p ist größer als q <- und davon können wir ja wohl ausgehen, oder? Okay, ich war jetzt zu faul den Fall (gleich =) zu berücksichtigen, aber der wird auch abgedeckt.
m.f.g.
BoMbY
Edit: PS: Klar, das ist nicht schneller wenn man einen Primfaktor findet, nur wenn man keinen findet!
Sargnagel
Commodore Special
- Mitglied seit
- 31.12.2001
- Beiträge
- 477
- Renomée
- 1
Sicher ist es schneller zu quadrieren, als die Wurzel zu ziehen. Aber da Number in der while-Schleife nicht verändert wird, braucht die Berechnung nur einmal pro Aufruf der Funktion Search2PrimFacts() durchgeführt zu werden. Dann sollte sich das wieder relativieren, es sei denn Du rufst besagte Funktion sehr oft (!) auf.Original geschrieben von [ab]noname
Das zählen bis zur Quadratwurzel ist eigentlich schon in meiner IsPrime Funktion integriert und vergleich auch nicht das Quadrat, sondern das Produkt, da Wurzelziehen langsamer ist, als ein Produkt zu berechnen:
- i*i <= Number ist äquivalent zu i <= sqrt(Number), jedoch schneller!
Theoretisch sollte der Compiler den Quellcode dahingehend optimieren, daß die angesprochene Berechnung auch nur einmal durchgeführt wird, aber zur Sicherheit solltest Du das mal austesten, indem Du round(sqrt(Number)) vor der while-Schleife berechnest.
[EDIT]
Und die Boolsche Variable brauchst Du auch nicht. Einfach mit break die Schleife beenden. Dadurch sparst Du pro Durchlauf einen Test (!found).
Code:
void Search2PrimFacts(i64 Number) {
i64 i = 3, // naja, die zwei ist ja fast wirklich egal
tmp;
tmp = round(sqrt(Number));
while ( i <= tmp)
{
if (isPrime(i))
{
if (Number % i == 0)
{
printf("%I64d*%I64d=%i64d\n", i, Number / i, Number);
[b]break; [/b]
}
}
i += 2;
}
}
Nur mal so ne generelle Frage,
brecht ihr nach der ersten Möglichkeit ab, oder lasst
ihr alle Möglichkeiten ausrechnen
Wenn ich aber Zeiten von 6s sehe, denke ich, dass nach der
1. gefundenen Möglichkeit abgebrochen wird.
Interessant wird IMHO aber erst wenn man alle sucht,
das dauert dann wirklich mal nen paar Stunden für so Zahlen wie oben genannt.
brecht ihr nach der ersten Möglichkeit ab, oder lasst
ihr alle Möglichkeiten ausrechnen
Wenn ich aber Zeiten von 6s sehe, denke ich, dass nach der
1. gefundenen Möglichkeit abgebrochen wird.
Interessant wird IMHO aber erst wenn man alle sucht,
das dauert dann wirklich mal nen paar Stunden für so Zahlen wie oben genannt.
Sargnagel
Commodore Special
- Mitglied seit
- 31.12.2001
- Beiträge
- 477
- Renomée
- 1
Hmm .. ich habe gerade Deinen Sourcecode ein paar Postings weiter oben entdeckt. Da hast Du das ja schon ganz anders geregelt. Jetzt sehe ich Deinen vorherigen Kommentar in einem ganz anderen Lichte.Original geschrieben von [ab]noname
In der Funktion IsPrime sollte das schon einen Geschwindigkeitsvorteil bringen. In der äußeren Schleife hast du dagegen Recht.
Ich lasse mal meine grauen Zellen ackern, was da eventuell noch zu optimieren ist ...
[EDIT]
Code:
for(i64 d = 2; d*d <= nr+1; d++)
[/EDIT]
Zuletzt bearbeitet:
Sargnagel
Commodore Special
- Mitglied seit
- 31.12.2001
- Beiträge
- 477
- Renomée
- 1
Da ist doch was faul ... nämlich der Compiler. Wie ich oben schon schrieb, führe die Berechnung der Wurzel doch mal vor der Schleife aus. Ich habe das ungute Gefühl, das für jeden Durchlauf der while-Schleife die Wurzelberechnung beim Test der Schleifenbedingungen erneut ausgeführt wird, was natürlich ein Performancefresser ist!Original geschrieben von [ab]noname
Selbst n-faches Quadrieren ist bei Zahlen dieser Größenordnung schneller als die Wurzel ziehen.
Code:
bool IsPrime(i64 nr) {
i64 tmp = ((i64)sqrt(nr))+1;
for(i64 d = 2; d <= tmp; d++) {
if (!(nr % d)) {
return false;
}
}
return true;
}
Und die Funktion sollte doch sicherlich bool und nicht long zurückgeben?
mj
Technische Administration, Dinosaurier, ,
- Mitglied seit
- 17.10.2000
- Beiträge
- 19.529
- Renomée
- 272
- Standort
- Austin, TX
- Mein Laptop
- 2,4kg schwer
- Prozessor
- eckig... glaub ich
- Mainboard
- quadratisch, praktisch, gut
- Kühlung
- kühler?
- Speicher
- ja
- Grafikprozessor
- auch
- Display
- viel bunt
- HDD
- ist drin
- Optisches Laufwerk
- ist auch drin (irgendwo)
- Soundkarte
- tut manchmal tuuut
- Gehäuse
- mit aufkleber!
- Netzteil
- so mit kabel und so... voll toll
- Betriebssystem
- das eine da das wo dingenskirchen halt, nech?
- Webbrowser
- so ein teil da... so grün und so
- Verschiedenes
- nunu!
Das war die erste Fassung, ja. Hat Vorteile, wenn man mehrere Zahlen hintereinander testen will weil dann nur einmal das Array durchlaufen wird was mit einer Komplexität von O geschieht.Original geschrieben von [ab]noname
D'Espice liest erstmal die Primzahlen in ein Array so wie ich das verstanden habe - berechnen muss man sie aber dennoch. Bei mir wird halt pro Primzahl getestet, wie es sich mit dem 2. Faktor der bei einer Division entsteht verhält. - kein Plan, warum das so hinkt
Die zweite Version, auf BigInteger basierend ist bei einzelnen Zahlen viel schneller da erst getestet wird, ob die Zahl modulo Schleifenzähler gleich Null ist. Ist dem nicht so, wird der Schleifenzähler erhöht und weitergemacht, ist dem so wird getestet, ob der Schleifenzähler eine Primzahl ist (BigInteger.isProbablePrime()) und ist auch das erfüllt, dann wird geschaut ob die Zahl geteilt durch Schleifenzähler auch eine Primzahl ist - wenn das alles zutrifft (schön der Reihe nach), dann haben wir ein Ergebnis.
Sargnagel
Commodore Special
- Mitglied seit
- 31.12.2001
- Beiträge
- 477
- Renomée
- 1
Jaja, okay. Ich seh's ja ein. Hatte aus den Augen verloren, daß isPrime() andauernd aufgerufen wird. *kippt Asche über's eigene Haupt* Da es sich um eine Integer-Wurzel handelt, muß es doch haufenweise Optimierungen für eine solche Berechnung geben! Vielleicht sogar mit Hilfe von MMX. Was sagen denn die AMD bzw. Intel TechDocs? Steht da zufällig schon eine Musterlösung drin?Original geschrieben von [ab]noname
Hab die Wurzel ausgelagert, 330s... Das optimiert auch jeder anständige Compiler.
Ich bin fest der Überzeugung, dass ein FP Sqrt viel zu viel Zeit braucht, als ne (vergleichsweise) simple Multiplikation, gleich, dass sie vielfach vorkommt.
Habs auch erst nicht geglaubt, aber die Code zeigts doch?
mj
Technische Administration, Dinosaurier, ,
- Mitglied seit
- 17.10.2000
- Beiträge
- 19.529
- Renomée
- 272
- Standort
- Austin, TX
- Mein Laptop
- 2,4kg schwer
- Prozessor
- eckig... glaub ich
- Mainboard
- quadratisch, praktisch, gut
- Kühlung
- kühler?
- Speicher
- ja
- Grafikprozessor
- auch
- Display
- viel bunt
- HDD
- ist drin
- Optisches Laufwerk
- ist auch drin (irgendwo)
- Soundkarte
- tut manchmal tuuut
- Gehäuse
- mit aufkleber!
- Netzteil
- so mit kabel und so... voll toll
- Betriebssystem
- das eine da das wo dingenskirchen halt, nech?
- Webbrowser
- so ein teil da... so grün und so
- Verschiedenes
- nunu!
Naja nein, nicht wirklich. Das ziehen einer Wurzel ist einfach extrem aufwändig.
@[ab]noname:
Für welche Zahl braucht dein Algorithmus 330s? Die erste der von JKuehl genannten? Wenn ja, dann musst du noch sehr viel optimieren, ich bin da mit Java bereits bei unter 7s angekommen
Du kannst deinen Algorithmus extrem beschleunigen, indem du die Reihenfolge bei der Abfrage umdrehst. Du prüfst derzeit zunächst für jede beliebige Zahl ob sie Prim ist und erst dann, ob sie Modulo Null ergibt - dreh das um! Es reicht wenn du nur die Zahlen auf prim prüfst, die wirklich Modulo gerechnet auch Null ergeben. Das spart dir unglaublich viel Zeit ein, du wirst erstaunt sein.
@[ab]noname:
Für welche Zahl braucht dein Algorithmus 330s? Die erste der von JKuehl genannten? Wenn ja, dann musst du noch sehr viel optimieren, ich bin da mit Java bereits bei unter 7s angekommen
Du kannst deinen Algorithmus extrem beschleunigen, indem du die Reihenfolge bei der Abfrage umdrehst. Du prüfst derzeit zunächst für jede beliebige Zahl ob sie Prim ist und erst dann, ob sie Modulo Null ergibt - dreh das um! Es reicht wenn du nur die Zahlen auf prim prüfst, die wirklich Modulo gerechnet auch Null ergeben. Das spart dir unglaublich viel Zeit ein, du wirst erstaunt sein.
Sargnagel
Commodore Special
- Mitglied seit
- 31.12.2001
- Beiträge
- 477
- Renomée
- 1
Jo, hab's gerade gefunden:Original geschrieben von D'Espice
Naja nein, nicht wirklich. Das ziehen einer Wurzel ist einfach extrem aufwändig.
http://www.azillionmonkeys.com/qed/sqroot.html
Eine einfache Quadrierung sollte in der Tat schneller sein, als die optimierteste Assembler-Version der Quadratwurzelberechnung von obiger Seite.
mj
Technische Administration, Dinosaurier, ,
- Mitglied seit
- 17.10.2000
- Beiträge
- 19.529
- Renomée
- 272
- Standort
- Austin, TX
- Mein Laptop
- 2,4kg schwer
- Prozessor
- eckig... glaub ich
- Mainboard
- quadratisch, praktisch, gut
- Kühlung
- kühler?
- Speicher
- ja
- Grafikprozessor
- auch
- Display
- viel bunt
- HDD
- ist drin
- Optisches Laufwerk
- ist auch drin (irgendwo)
- Soundkarte
- tut manchmal tuuut
- Gehäuse
- mit aufkleber!
- Netzteil
- so mit kabel und so... voll toll
- Betriebssystem
- das eine da das wo dingenskirchen halt, nech?
- Webbrowser
- so ein teil da... so grün und so
- Verschiedenes
- nunu!
Na siehste, geht dochOriginal geschrieben von [ab]noname
Hrhr der Modulo Trick
Jetzt hab ichs auf t = 0 bis 1sec für die 1. Zahl - Yippieeh! thx D'Espice
Jetzt muss ich wieder kontern, meine 7s wurden unterboten. Leider wird das wohl kaum möglich sein, da BigInteger einfach extrem lahm ist. Aber ich werd heut Nacht überlegen, ob sich da noch was drehen und optimieren lässt.
Was ich mir überlegt habe ist ein Feld anzulegen, welches alle Zahlen enthält die bereits als negativ geprüft wurden. Für jede neue Zahl kann dann zunächst geprüft werden, ob sie ein Vielfaches einer der bereits gespeicherten Zahlen ist. So kann man sich nochmals einige hundertausend Rechnungen sparen.
mj
Technische Administration, Dinosaurier, ,
- Mitglied seit
- 17.10.2000
- Beiträge
- 19.529
- Renomée
- 272
- Standort
- Austin, TX
- Mein Laptop
- 2,4kg schwer
- Prozessor
- eckig... glaub ich
- Mainboard
- quadratisch, praktisch, gut
- Kühlung
- kühler?
- Speicher
- ja
- Grafikprozessor
- auch
- Display
- viel bunt
- HDD
- ist drin
- Optisches Laufwerk
- ist auch drin (irgendwo)
- Soundkarte
- tut manchmal tuuut
- Gehäuse
- mit aufkleber!
- Netzteil
- so mit kabel und so... voll toll
- Betriebssystem
- das eine da das wo dingenskirchen halt, nech?
- Webbrowser
- so ein teil da... so grün und so
- Verschiedenes
- nunu!
Unter Linux kann ich das genau messen, ich werd gleich versuchen ob ich deinen Quellcode mit gcc compilieren kann und wenn ja, sag ich dir die genaue Zeit auf dem Opteron für den Algorithmus
EDIT:
Mir fällt grad ein, wird eh nix bringen. Denn gcc kann mit __int64 nix anfangen und long ist zu klein für diese Zahl. Vergessen wir die Linux-Idee also gleich wieder
EDIT:
Mir fällt grad ein, wird eh nix bringen. Denn gcc kann mit __int64 nix anfangen und long ist zu klein für diese Zahl. Vergessen wir die Linux-Idee also gleich wieder
Sargnagel
Commodore Special
- Mitglied seit
- 31.12.2001
- Beiträge
- 477
- Renomée
- 1
Kein Problem:Original geschrieben von D'Espice
EDIT:
Mir fällt grad ein, wird eh nix bringen. Denn gcc kann mit __int64 nix anfangen und long ist zu klein für diese Zahl. Vergessen wir die Linux-Idee also gleich wieder
Code:
[b]long long[/b] number;
[...]
Search2PrimFacts(1949565409282837[b]LL[/b]);
@GMP-Library:
Das ist ganz easy und die Library ist auch schön schnell.
Sargnagel
Commodore Special
- Mitglied seit
- 31.12.2001
- Beiträge
- 477
- Renomée
- 1
So, hier ist meine Version mit der GMP-Library. Da ist noch nix entsprechend optimiert. Es müßte noch die Anzahl der Aufrufe der mpz_init()-Funktion in der IsPrime()-Funktion drastisch verringert werden und was weiß ich noch alles, um mehr Performance zu erreichen, aber dafür habe ich leider keine Zeit mehr.
Ein paar print-Befehle zum Debuggen habe ich mal nicht gelöscht.
Viel Spaß damit.
[EDIT]
Ich habe mal die Search2PrimeFacts() Funktion leicht abgewandelt in Anlehnung an BoMbY's Beweis. Die Berechnungsdauer für "312133288776418481" wurde um etwas mehr als die Hälfte gesenkt.
[/EDIT]
Code:
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <math.h>
#include <gmp.h>
bool IsPrime(mpz_t nr) {
mpz_t d, tmp;
mpz_init(d);
mpz_init(tmp);
mpz_set_ui(d, 2);
mpz_pow_ui(tmp, d, 2);
//printf("IsPrime\n");
while(mpz_cmp(tmp, nr) <= 0) {
//gmp_printf("d=%Zd, tmp=%Zd\n", d, tmp);
if(mpz_divisible_p(nr, d))
return false;
mpz_add_ui(d, d, 1);
mpz_pow_ui(tmp, d, 2);
}
return true;
}
void Search2PrimeFacts(mpz_t number) {
mpz_t a, i, tmp;
mpz_init(a);
mpz_init(i);
mpz_init(tmp);
mpz_set_ui(i, 3);
mpz_sqrt(tmp, number);
while(mpz_cmp(i, tmp) <= 0) {
if(mpz_divisible_p(number, i)) {
if(IsPrime(i)) {
mpz_cdiv_q(a, number, i);
if(IsPrime(a)) {
gmp_printf("%Zd * %Zd = %Zd\n", a, i, number);
break;
}
}
}
mpz_add_ui(i, i, 2);
}
}
int main(void) {
float millisecs;
clock_t start, end;
mpz_t number;
mpz_init(number);
mpz_set_str(number, "312133288776418481", 10);
start = clock();
Search2PrimeFacts(number);
end = clock();
millisecs = (float)(end - start)/((float)CLOCKS_PER_SEC/1000);
printf("Elapsed time in milliseconds: %f\n", millisecs);
return 0;
}
Viel Spaß damit.
[EDIT]
Ich habe mal die Search2PrimeFacts() Funktion leicht abgewandelt in Anlehnung an BoMbY's Beweis. Die Berechnungsdauer für "312133288776418481" wurde um etwas mehr als die Hälfte gesenkt.
[/EDIT]
Zuletzt bearbeitet:
DarkAvenger
Commodore Special
- Mitglied seit
- 20.05.2003
- Beiträge
- 391
- Renomée
- 0
Ich hoffe, es ist bekannt, daß Primzahltest in NP (und sogar coNP) liegt und die gängigen Alg auch nicht darüberhinaus kommen? Ein Bekannter hat mir zwar gesagt, daß es mittlerweile einen O(N) Algorithmus gibt, aber der soll wohl erst bei Zahlen mit einigen Dutzend (oder waren es hundert?) Nullen, schneller sein, als die bisher bekannten...aufgrund einer groooooßen Konstate vor dem "n".
Ist es nicht stupide, irgendwelche Algorithmen zu implementieren, ohne sich schlau zu machen, was es für Alg gibt bzw. ohne großartig Theorie zu verstehen, dumm draufloszucoden? Etwa das Mersenne Prime Projekt liefert interessante und vor allem schnelle Algorithmen....da zu optimieren wäre interessanter und auch von bleibenden Wert.
Naja, mehr als Beschäftigungstherapie wird das so nicht werden...
Ist es nicht stupide, irgendwelche Algorithmen zu implementieren, ohne sich schlau zu machen, was es für Alg gibt bzw. ohne großartig Theorie zu verstehen, dumm draufloszucoden? Etwa das Mersenne Prime Projekt liefert interessante und vor allem schnelle Algorithmen....da zu optimieren wäre interessanter und auch von bleibenden Wert.
Naja, mehr als Beschäftigungstherapie wird das so nicht werden...
Ähnliche Themen
- Antworten
- 0
- Aufrufe
- 182
- Antworten
- 8
- Aufrufe
- 4K
- Gesperrt
- Antworten
- 2K
- Aufrufe
- 179K
- Antworten
- 46
- Aufrufe
- 29K
- Antworten
- 10
- Aufrufe
- 4K