| Autor |
Beitrag |
patrick
      
Beiträge: 1481
WIN2k, WIN XP
D6 Personal, D2005 PE
|
Verfasst: So 28.11.04 19:50
ich hab den output mal überfolgen: die zahlen wo ich gesehen hab stimmen.
ich hab gerade versucht den code von GTA-Place per assembler zu verschnellern.
bei der suche nach einem noch schnelleren code zum wurzel ziehen bin ich auf diesen code gestoßen:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90:
| function IsPrime(N: Cardinal): Boolean; register; asm TEST EAX,1 JNZ @@1 CMP EAX,2 SETE AL RET @@1: CMP EAX,73 JB @@C JE @@E PUSH ESI PUSH EDI PUSH EBX PUSH EBP PUSH EAX LEA EBP,[EAX - 1] MOV ECX,32 MOV ESI,EBP @@2: DEC ECX ADD ESI,ESI JNC @@2 PUSH ECX PUSH ESI CMP EAX,08A8D7Fh JAE @@3 MOV EAX,31 CALL @@5 JC @@4 MOV EAX,73 PUSH OFFSET @@4 JMP @@5 @@3: MOV EAX,2 CALL @@5 JC @@4 MOV EAX,7 CALL @@5 JC @@4 MOV EAX,61 CALL @@5 @@4: SETNC AL ADD ESP,4 * 3 POP EBP POP EBX POP EDI POP ESI RET @@5: MOV EBX,[ESP + 12] MOV ECX,[ESP + 8] MOV ESI,[ESP + 4] MOV EDI,EAX @@6: DEC ECX MUL EAX DIV EBX MOV EAX,EDX ADD ESI,ESI JNC @@7 MUL EDI DIV EBX AND ESI,ESI MOV EAX,EDX @@7: JNZ @@6 CMP EAX,1 JE @@A @@8: CMP EAX,EBP JE @@A DEC ECX JNG @@9 MUL EAX DIV EBX CMP EDX,1 MOV EAX,EDX JNE @@8 @@9: STC @@A: RET @@B: DB 3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71 @@C: MOV EDX,OFFSET @@B MOV ECX,18 @@D: CMP AL,[EDX + ECX] JE @@E DEC ECX JNL @@D @@E: SETE AL end; |
Quelle
resultat:
10 millionen durchläufe haben mit dem letzten GTA-Code bei mir 6,4 sekunden gebraucht.
dieser code braucht dafür gerademal 0,3 sekunden
dennoch eine weitere optimierung des delphi-codes wäre bestimme interessant.
purer und intelligent geschriebener asm-code ist halt nicht zu schlagen wenn es um mathematik geht.
_________________ Patrick
im zweifelsfall immer das richtige tun!!!
|
|
GTA-Place
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: So 28.11.04 20:15
Bei mir was der ASM-Code langsamer.
Es gibt ein Problem beim Überprüfen von Zahlen zw. 0 und 100:
| Zitat: | | Access violation at 0x004059c1: write of address 0x00030e68 |
Hab ein paar Änderungen vorgenommen:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72:
| procedure TMainForm.StartButClick(Sender: TObject); var Start, Ende: Real; Z: PCardinal; X, Y, LPrim: Cardinal; PrimF: TStringList; CountP: String; begin try Von := StrToInt(VonEdit.Text); Bis := StrToInt(BisEdit.Text);
if Bis > 10 then SetLength(PrimS, Trunc(0.4*Bis-(Bis/4))) else SetLength(PrimS, 4);
LPrim := 0; Z := @PrimS[0]; Y := 0; if (Von >= 0) AND (Bis >= 0) AND (Von < Bis) then begin Start := GetTickCount;
for X := Von to Bis do begin if Prim(X) then begin Z^ := X; Inc(Z); Inc(Y); LPrim := X; end; if X mod 20000 = 0 then begin Application.ProcessMessages; PrimLab.Caption := 'Aktuelle Primzahl: ' + IntToStr(LPrim); end; end;
Ende := GetTickCount; DauerLab.Caption := 'Diese Überprüfung hat ' + FloatToStr((Ende - Start) / 1000) + ' Sekunden gedauert.';
CountP := IntToStr(Y); PrimLab.Caption := 'Speichern... (0 / ' + CountP + ')';
PrimF := TStringList.Create;
for X := 0 to Length(PrimS)-1 do begin if PrimS[X] = 0 then Break; if X mod 1000 = 0 then begin Application.ProcessMessages; PrimLab.Caption := 'Speichern... (' + IntToStr(X+1) + ' / ' + CountP + ')'; end; PrimF.Add(IntToStr(PrimS[X])); end;
PrimF.SaveToFile('Paket.prim'); PrimF.Free;
PrimLab.Caption := 'Aktuelle Primzahl: ' + IntToStr(LPrim); end else ShowMessage('Ungültige Eingabe(n)!'); except ShowMessage('Es ist ein Fehler aufgetreten!'); end; end; |
|
|
Phantom1
      
Beiträge: 390
|
Verfasst: So 28.11.04 20:47
Ich hab den ASM-Code auch mal getestet bei 10 millionen testdurchläufen: 4,7 sekunden
GTA-Place dagegen: 6,8 sekunden
Ich denke das bekommen wir noch hin ;O)
Ein nachteil gibt es jedoch mit dem Code von GTA-Place, es muss immer von 0 bzw 2 begonnen werden bis zur gewünschten Testzahl.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: So 28.11.04 21:13
OK, an die 16 Sekunden für 20 Mio. komm ich mit meinem Code noch net so richtig ran (37.5s, dafür aber auf 1,4GHz)
Hab vorhin mal die Prüfung auf 1Mrd. gemacht: Ergebnis 01:57:29.733 mit 141849 Zahlen\Sekunde und 50847 534 gefundenen Primzahlen.
Weiterhin ist bei meinem Source noch zu beachten, dass ich dafür Int64-Operationen nutze. Die Wurzel lass ich mir per FPU ziehen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| Asm FILD QWORD PTR [CurrNum] FSQRT FISTP QWORD PTR [MaxTest] End; |
Wobei ich vor der Schleife die FPU generell auf Abrunden umschalte:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| Asm FLDCW WORD PTR [@@TruncCW] JMP @@Skip @@TruncCW: DW $1772 @@Skip: End; |
@GTA: Du hattest vorhin die markierte 5 doppelt...
Könntet Ihr aber mal bei Performance-Informationen die CPU\Takt und RAM angeben? Ich glaub, das hilft bei der Einstufung der Messwerte schon um einiges Weiter.
Aber ehrlichgesagt: An den ASM-Source komm ich bei weitem net ran ... 
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
GTA-Place
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: So 28.11.04 23:43
EDIT: Problem gelöst, "Inc(Z);" hat gefehlt.
|
|
Phantom1
      
Beiträge: 390
|
Verfasst: Mo 29.11.04 10:24
Ich glaube wir sind noch sehr weit vom Optimum entfernt, schaut doch mal in dieses Forum/Thread: www.forum-3dcenter.o...1&highlight=prim
die kommen dort ohne probleme auf folgende Zeiten:
1Mio : 0,02s
5Mio : 0,09s
10Mio : 0,2s
50Mio : 1,1s
100Mio : 2,5s
500Mio : 17,2s
1Mrd : 43s
2^32-cache : 7,5min
Auf Seite 4 des Thread's, erfährt man sogar das es noch viel schneller geht ;O) Ich sag nur primegen.
mfg
|
|
Phantom1
      
Beiträge: 390
|
Verfasst: Mo 29.11.04 13:03
Ich habe eben auch nochmal einen neuen Code nach dem SIEB DES ERATOSTHENES geschrieben:
für 10 Mio testzahlen braucht mein Code etwa 0,65 Sekunden (ohne speichern)
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| procedure SavePrimes(MaxPrime: Cardinal; const FileName: String = ''); var isPrime: Array of Boolean; i, j: Cardinal; SL: TStringList; begin SetLength(isPrime, MaxPrime+1); FillChar(isPrime[2], Length(isPrime)-2, 1); for i:=2 to Trunc(Sqrt(MaxPrime)) do if isPrime[i] then begin j:=i*2; while j<=MaxPrime do begin isPrime[j]:=False; Inc(j, i); end; end;
if FileName<>'' then begin SL:=TStringList.Create; try for i:=2 To MaxPrime do if isPrime[i] then SL.Add(IntToStr(i)); SL.SaveToFile(FileName); finally FreeAndNil(SL); end; end; end; |
Zuletzt bearbeitet von Phantom1 am Di 30.11.04 23:00, insgesamt 1-mal bearbeitet
|
|
GTA-Place
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: Mo 29.11.04 16:23
www.delphipraxis.net...ic40427,0,asc,0.html
| sakura hat folgendes geschrieben: | | Mein Lieblingsalgorithmus findest Du im Projekt im Anhang, das Sieb des Erasthothes od so Alle Primzahlen zw. 1 und 10.000.000 findet der Algorithmus bei mir in weniger als 1,5 Sekunden |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| FillChar(PrimeGrid, SizeOf(PrimeGrid), #1); PrimeGrid[1] := False; for CurrPrimeCandidate := 2 to MAX_PRIME do begin if PrimeGrid[CurrPrimeCandidate] then begin NotAPrime := CurrPrimeCandidate * 2; while NotAPrime <= MAX_PRIME do begin PrimeGrid[NotAPrime] := False; Inc(NotAPrime, CurrPrimeCandidate); end; end; end; |
|
|
Tilo
      
Beiträge: 1098
Erhaltene Danke: 13
Win7 geg. WInXP oder sogar Win98
Rad2007
|
Verfasst: Di 30.11.04 16:53
Okay, habe mal meinen Code umgestellt.
Ein grund wieso meine Routine so langsam war ist, das ich es über Application.Onidle hab laufen lassen.
Wenn ich den Code so um schreibe, das bei jeder 10000 Primzahl eine Programmabgabe wie bei GTA-Place, dann schafft mein Programm 10.000.000 Primzahlen unter 0,5 Sekunden
der Code:
Edit2: Schnellschuss meinerseits, Code liefert keine Primzahlen.
Zuletzt bearbeitet von Tilo am Di 30.11.04 21:41, insgesamt 2-mal bearbeitet
|
|
F34r0fTh3D4rk
      
Beiträge: 5284
Erhaltene Danke: 27
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 30.11.04 17:20
ich werf hier mal wieder was ausm edh rein (falls nich schon vorhanden):
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| Function IsPrim(zahl : Integer): boolean; var i: integer; begin result := true; If zahl = 1 then begin result := false; exit; end; For i := 2 to (zahl div 2) do begin If ((zahl mod i) = 0) then begin result := false; exit; end; end; end; |
Wie sieht bei euch der aufruf aus ?
|
|
GTA-Place
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: Di 30.11.04 17:22
Delphi-Quelltext 1:
| For i := 2 to (zahl div 2) do |
Das muss langsamer sein, denn man muss gar nicht zu Hälfte der Zahl, sondern nur bis zur Wurzel der Zahl prüfen.
|
|
F34r0fTh3D4rk
      
Beiträge: 5284
Erhaltene Danke: 27
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 30.11.04 19:19
zufällig war ich auch gerade dabei sowas zu machen, war mir dann aber doch zu langsam
und beim integer maximum schmiert er ja bekanntlich ab...
Ich habe gehört, dass es eine Belohnung geben soll, wenn man eine 100 Stellige
Primzahl findet, also ranhalten jungs !!! 
|
|
Tilo
      
Beiträge: 1098
Erhaltene Danke: 13
Win7 geg. WInXP oder sogar Win98
Rad2007
|
Verfasst: Di 30.11.04 21:43
|
|
patrick
      
Beiträge: 1481
WIN2k, WIN XP
D6 Personal, D2005 PE
|
Verfasst: Di 30.11.04 21:46
dann müsten wir ja nur den 100-stelligen bereich durchgehen. dann verteilen wir auch noch die bereiche und dann ist alles halb so schlimm. wieviel 100jahre würden wir brauchen? 
_________________ Patrick
im zweifelsfall immer das richtige tun!!!
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 30.11.04 21:57
6 Monate, unter der Annahme, dass wir die Suchbereiche effektiv nutzen.
In Hinblick auf die Ermittlung brauchen wir ja um eine 100-Stellige Zahl auf Primalität zu prüfen nicht wirklich alle Zahlen zu testen.
Es würde reichen, wenn wir Sagen wir SPPs zur Basis der ersten 1000 Primzahlen durchführen. Dann dürften wir auf jeden Fall auf der sicheren Seite sein 
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Phantom1
      
Beiträge: 390
|
Verfasst: Mi 01.12.04 12:58
Ich habe mein code jetzt nochmal optimiert.
Für 10 mio testzahlen dauerts jetzt nur noch 0,3 sekunden, nebenbei habe ich noch den Speicherverbrauch auf ein 1/8 reduziert.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
| procedure SavePrimes(MinPrime, MaxPrime: Cardinal; const FileName: String = ''); var isPrime: Array of Cardinal; i, j: Cardinal; SL: TStringList; begin SetLength(isPrime, MaxPrime div 32); FillChar(isPrime[0], Length(isPrime)*SizeOf(Cardinal), MAXBYTE); isPrime[0]:=$FFFFFFFC; for i:=2 to Trunc(Sqrt(MaxPrime)) do if isPrime[i div 32] shr (i mod 32) and 1=1 then begin j:=i*2; while j<=MaxPrime do begin isPrime[j div 32]:=isPrime[j div 32] and not (1 shl (j mod 32)); Inc(j, i); end; end;
if FileName<>'' then begin SL:=TStringList.Create; try for i:=MinPrime To MaxPrime do if isPrime[i div 32] shr (i mod 32) and 1=1 then SL.Add(IntToStr(i)); SL.SaveToFile(FileName); finally FreeAndNil(SL); end; end; end; |
mfg
|
|
Tilo
      
Beiträge: 1098
Erhaltene Danke: 13
Win7 geg. WInXP oder sogar Win98
Rad2007
|
Verfasst: Mi 06.04.05 17:21
Ich weiss, das dieses Thema alt ist.
Ich habe ich aber mal mit Pointern beschäftigt.
Ich habe mal die "prim" function von GTA-Place um geschrieben:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| function tform1.Prim(Zahl: LongInt): Boolean; var Teiler, Wurzel: LongInt; p1prim:PTprim; begin Result := True; p1prim:=startprim; if (not odd(Zahl)) OR (Zahl <= 5) then begin if (Zahl <> 2) AND (Zahl <> 3) AND (Zahl <> 5) then Result := False; Exit; end; Wurzel := Trunc(sqrt(Zahl)); while (p1prim^.prim <= Wurzel) AND (Result) do begin if Zahl mod p1prim^.prim = 0 then Result := False; p1prim:=p1prim^.nextprim; end; end; |
Bitte hiermit aufrufen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| if prim(zutesten) then begin new(P1prim); p1prim^.nextprim:=nil; lastprim^.nextprim:=p1prim; p1prim^.prim:=zutesten; lastprim:=p1prim; inc(zutesten) end; |
zum Intialisieren bitte das verwenden:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.FormCreate(Sender: TObject); var a,b,c:integer; p1prim:PTprim; begin new(startprim); new(P1prim); startprim^.prim:=2; startprim^.nextprim:=P1prim; p1prim^.prim:=3; p1prim^.nextprim:=nil; lastprim:=p1prim; end; |
Das Ende ist dann wie folgt:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); var p1prim,p2prim:PTprim; begin p1prim:=startprim; while p1prim^.nextprim<>nil do begin p2prim:=p1prim; p1prim:=p1prim^.nextprim; dispose(p2prim); end; dispose(p1prim); end; |
Wichtig ist noch
Delphi-Quelltext 1: 2: 3: 4: 5:
| PTPrim=^TPrim; TPrim =record prim:integer; nextprim:PTPrim; |
Lastprim und Startprim sind globale PTPrim.
HOffe keinen Nonsens zu posten
Moderiert von Christian S.: Code- durch Delphi-Tags ersetzt.
|
|
GTA-Place
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: Mi 06.04.05 17:27
Isses schneller?
_________________ "Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
|
|
Tilo
      
Beiträge: 1098
Erhaltene Danke: 13
Win7 geg. WInXP oder sogar Win98
Rad2007
|
Verfasst: Do 07.04.05 13:56
Bei meinen Programm bringt es bei der berechnung der ersten 1000 Primzahlen einen Zeitvorteil von 10 bis 20 ms als mit der Verwendung eines statischen Feldes.
Vorteil der Pointer-Methode:
- Das "Feld" wird nach Bedarf aufgebaut ->Vorteil, da Speicherbelastung geringer.
Wenns nicht schneller wäre hätte ich es nicht gepostet.
|
|
Omikron2
Hält's aus hier
Beiträge: 14
win xp
d6 k.a.edition
|
Verfasst: Fr 08.04.05 23:59
Es gibt seit 2002 glaube ich einen algorithmus der zahlen auf prim überprüft und nur einen linearen rechenaufwand hat (es müssen nicht mehr alle möglichkeiten ausprobiert werden) googlen hilft vielleicht!
mfg
|
|
|