Primzahlen von 0 bis n
Ich möchte mit einem Programm alle Primzahlen von 0 und bis zu einer eingegebenen Grenze herausfinden.
An sich klappt das auch ganz gut. Allerdings habe ich dass Problem, dass ich bei einem Durchgang von 0 bis 1.000.000.000 bspw. knapp 1 GB Arbeitsspeicher benötige. Theoretisch könnte ich ja 1/8 des benötigten Rams sparen, wenn ich für jede Boolean-Variable nur ein Bit benötigen würde. (Imho benötigt eine Boolsche Variable bei Delphi 1 Byte.) Allerdings fällt mir dazu keine schnelle Lösung ein. Lediglich:
Delphi-Quellcode:
was aber nicht allzu schnell sein dürfte.
var
i: Byte; ... if i and 1 shl x ... Zusätzlich zu diesem Arbeitsspeicher-Problem würden mich auch noch Vorschläge für Verbesserungen der Geschwindigkeit interessieren. Gern auch in Assambler (Wenn es 'ne ausführliche Erklärung dabei gibt :wink: ) Jetzt aber erstmal mein Quelltext (Ich habe ihn mal ein wenig kommentiert):
Delphi-Quellcode:
PS: Es ist mir klar, dass es schon einige Beiträge zu Primzahlen in der DP gibt, mir geht es jedoch direkt um die Optimierung meines Programms.
program Primzahlengenerator;
{$APPTYPE CONSOLE} uses Classes, Windows; var IsPrim: array of Boolean; j, k, Max, HalfMax: Int64; s: String; F: TMemoryStream; Time, Time2: Cardinal; begin Writeln('Bitte geben sie eine obere Grenze ein: '); Readln(Max); Writeln('Bitte geben sie eine Datei an,' + ' in der die Primzahlen gespeichert werden sollen:'); Readln(s); Time := GetTickCount; SetLength(IsPrim, Max); // Länge der Arrays festlegen j := 2; while j < Max do // Vorerst alle Zahlen als Primzahlen markieren begin IsPrim[j] := True; Inc(j); end; HalfMax := Max div 2; // Die Hälfte der Grenze speichern, so dass diese folgend nicht mehr // errechnet werden muss F := TMemoryStream.Create; j := 2; while j <= HalfMax do // Die halbe Liste durchgehen begin if IsPrim[j] then begin F.Write(j, 4); // Zahl im MemoryStream schreiben k := j shl 1; // Startwert ist das doppelte der aktuellen Zahl (j) while k < Max do begin IsPrim[k] := False; // Alle Vielfachen der Zahl (j) als Nicht-Prim markieren Inc(k, j); // k auf das nächste Vielfache setzen end; end; Inc(j); end; // Die restlichen Primzahlen in den Stream schreiben while j < Max do begin if IsPrim[j] then F.Write(j, 4); Inc(j); end; F.SaveToFile(S); F.Free; // Benötigte Zeit ausgeben Time2 := GetTickCount; Time := Time2 - Time; Write(Time div 60000); Write(' Minuten '); Write((Time mod 60000) div 1000); Write(' Sekunden '); Write((Time mod 60000) mod 1000); Writeln(' Millisekunden'); end. EDIT: Über Bewertungen meines Programmes würde ich mich im übrigen auch freuen. |
Re: Primzahlen von 0 bis n
Zitat:
|
Re: Primzahlen von 0 bis n
Bitvektoren heißen die Dinger, die du meinst. Sie sind zwar nicht so schnell wie eine "richtige" Boolean-Variable, aber trotzdem nicht soo langsam. Wenn der Speicherverbrauch es rechtfertigt, dann nimm sie.
Im Übrigen wäre es evtl. einfacher, wenn du einfach die Primzahlen in einem optimierten Array (mit optimiert meine ich bei 100 anfangen und dann immer um das Doppelte vergrößern) alle benötigten Primzahlen speicherst. Wenn du dann wissen willst, ob eine Zahl eine Primzahl ist oder nicht, kannst du mit binärer Suche durchgehen. |
Re: Primzahlen von 0 bis n
Edit: war quark...
|
Re: Primzahlen von 0 bis n
Zitat:
Zitat:
Zitat:
Zitat:
EDIT: Zitat:
|
Re: Primzahlen von 0 bis n
Zitat:
|
Re: Primzahlen von 0 bis n
Na dann werd ichs gleich mal umbauen - Gut dass es hier immer Leute gibt, die einem über die eigenen Wissenslücken hinweghelfen :thumb:
So implementiert und ausprobiert: Verbraucht weniger Ram und is sogar noch deutlich schneller. -- Hat sonst noch jemand irgendeine Idee, was man verbessern könnte? EDIT2: Hab mir grad nochmal die implementation der Klasse TBits angeschaut:
Delphi-Quellcode:
Ich denke doch, dass ich einige Probleme bekomme, wenn ich die größe über MaxInt setze.
TBits = class
private FSize: Integer; FBits: Pointer; procedure Error; procedure SetSize(Value: Integer); procedure SetBit(Index: Integer; Value: Boolean); function GetBit(Index: Integer): Boolean; ... Daher hätte ich dann dovh eine maximale obere Grenze von 2.147.483.647. Oder übersehe ich da was? |
Re: Primzahlen von 0 bis n
@Hador,
ich habe interessehalber mal eine Assemblerversion geschrieben, die die Daten in einem Bitfeld speichert. Das ganze kann man noch optimieren a) im Prinzip braucht man die Daten nur für ungerade Zahlen speichern weil die einzige gerade natürliche Primzahl 2 ist, und die kann man ja separat prüfen b) die Geschwindigkeit kann man sicherlich noch deutlich erhöhen. hab nicht intensiv getestet...
Delphi-Quellcode:
var sieve:array of cardinal;
PROCEDURE CreateSieve(max:integer); var len:integer; PROCEDURE FillSieve; asm pushad mov edi,sieve // Adresse sieve[0] xor [edi],3 // Bit 0 und 1 löschen mov ebx,[edi-4] // Länge in Cardinals shl ebx,5 // Länge in Bits // ECX = P = Erste ungerade Primzahl mov ecx,3 mov eax,9 // P^2 // Beginnend bei P*P alle Vielfachen von P als nichtprim markieren @ClrBitLoop: btr [edi],eax // Bit löschen add eax,ecx // + P cmp eax,ebx // noch im gültigen Bereich ? jb @ClrBitLoop // ja // Nächsthöheres P suchen @NxtPrimeLoop: add ecx,2 // P:=P+2 bt [edi],ecx // Ist P prim ? jnc @NxtPrimeLoop // nein, nächstes P prüfen mov eax,ecx // P=Primzahl mul ecx // P^2 cmp eax,ebx // noch im gültigen Bereich jb @ClrBitLoop // ja, vielfache als nichtprim markieren @End: popad end; begin len:=max shr 5 + 1; SetLength(sieve,len); FillChar(sieve[0],len shl 2,$AA); SetLength(sieve,len); FillSieve; end; FUNCTION IsPrime(p:integer):boolean; asm mov ecx,sieve // Adresse sieve mov edx,[ecx-4] // Länge in Cardinal shl edx,5 // Länge in Bits cmp eax,edx jb @TestPrime xor eax,eax @TestPrime: bt [ecx],eax setc al end; |
Re: Primzahlen von 0 bis n
Erstmal vielen Dank. Ich werde mal versucher durch deinen Quelltext durchzublicken bzw. ihn zu verstehen.
Irgendwo hab ich hier auch noch 'n Assembler-Tutorial rumfliegen :) Zitat:
Falls ich irgendwo nicht weiterkomme in deinem Asm-Code, meld ich mich mal bei dir :wink: |
Re: Primzahlen von 0 bis n
ich habe mit meinem Programm innerhalb von eineinhalb stunden alle Prinzahlen von 1 bis 1Millionen gekriegt. wie lange braucht ihr?
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:50 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz