Autor |
Beitrag |
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: Di 23.04.13 21:47
IhopeonlyReader hat folgendes geschrieben : | würdest du mir allerdings helfen, wie ich eine Datei auf die Festplatte auslagere? |
Versuchs mit einem TFileStream. Mit einem TMemoryStream wird es nicht gehen (maximal die schon bekannten 1,5 GB). Ansonsten bliebe noch AssignFile und Co.
|
|
IhopeonlyReader 
      
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: Di 23.04.13 21:49
Gerd Kayser hat folgendes geschrieben : | Ansonsten bliebe noch AssignFile und Co. |
NEIN! ich caste keine 4 Billionen zahlen in Strings, schreibe sie, und lese/ändere sie dann noch paar mal ! das wären viel zu viele zugriffe.. das würde ca aus vorher 1 sek so ungefähr 1 min machen.. nein danke...
TfileStream ist hoffe ich mal schneller.. werde ich mir später anschauen..
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Zuletzt bearbeitet von IhopeonlyReader am Mi 24.04.13 21:24, insgesamt 2-mal bearbeitet
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: Di 23.04.13 22:50
IhopeonlyReader hat folgendes geschrieben : | TfileStream ist hoffe ich mal schneller.. |
Die Geschwindigkeit hängt davon ab, wie viele Bytes Du auf einen Rutsch liest oder wegschreibst. Je mehr, desto schneller. Einen solchen Block könntest Du z. B. als einen packed record definieren. In diesem gelesenen Block könntest Du dann die Bit-Operationen ausführen. Das spielt sich dann im RAM und nicht auf der Festplatte ab. Ist also bedeutend schneller, als wenn Du jedes einzelne Integer liest und schreibst.
|
|
IhopeonlyReader 
      
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: Mi 24.04.13 16:28
wie ich schon schrieb, habe ich (4 Mrd +7)er Blöce also 4Mrd +8 Bits = 500000001 Byte-Blöcke = 488281 KB = 476,84 MB = 0,466 GB Blöcke
würdest du bitte ein Beispiel machen?
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: Mi 24.04.13 20:44
IhopeonlyReader hat folgendes geschrieben : | würdest du bitte ein Beispiel machen? |
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:
| procedure TMainform.Button1Click(Sender: TObject); var Schleife : cardinal; ZahlByte : byte; Zahl : cardinal; FS : TFileStream; DatenBlock : array [0..124999] of byte; begin FS := TFileStream.Create('L:\Primzahlen.PRIM', fmOpenReadWrite or fmCreate); try for Schleife := 0 to 124999 do DatenBlock[Schleife] := $55; for Schleife := 1 to 80000 do FS.Write(DatenBlock, SizeOf(DatenBlock)); FS.Position := 0; FS.Read(ZahlByte, SizeOf(ZahlByte)); ZahlByte := ZahlByte xor $03; FS.Position := 0; FS.Write(ZahlByte, SizeOf(ZahlByte)); FS.Position := 10; Zahl := $12345678; FS.Write(Zahl, SizeOf(Zahl)); finally FS.Free; end; end; |
Ein paar Anmerkungen dazu.
1. Durch das Endian-Format wird die Bytefolge $12345678 als 78 56 34 12 in der Datei abgelegt.
2. Liest man einen Integer und rechnet "Integerwert xor 3", dann wird das höherwertigste Byte (ganz links) geändert und nicht das niederwertigste, was man ja erwarten würde. Deshalb lese und schreibe ich hier nur Bytes, keine Integer.
3. Durch ein Lesen oder Schreiben im FileStream wird der Positionszeiger erhöht. Deshalb vorher FileStream.Position setzen.
4. Beim Testen erst einmal mit kleineren Dateigrößen anfangen. Bei einem Testlauf habe ich eine 40 GB große Datei erzeugen können. Größer ging hier nicht, weil nicht genügend Platz auf der Partition war.
5. Da die Anwendung durch das Bearbeiten des großen Streams blockiert wird, empfiehlt es sich, das in einen Thread auszulagern.
6. Der Datenblock kann nicht beliebig vergrößert werden, sonst gibt es Probleme mit dem Heap.
|
|
IhopeonlyReader 
      
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: Mi 24.04.13 21:21
Gerd Kayser hat folgendes geschrieben : |
var
Schleife : cardinal; // int64 nicht möglich
|
doch wenn du dein
Delphi-Quelltext 1: 2: 3: 4:
| For Schleife:=1 to 80000 do begin end; |
gegen
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| Schleife := 1; while Schleife <= 80000 do begin inc(Schleife); end; |
tauscht..
aber danke für dein Beispiel  , weißt du wie lange das ca dauert, bis 0,5 Gb geschrieben/gelesen sind?
weil wenn ich das in ein extra thread packe, und der dann mit der Berechnung schneller ist, als mit dem schreiben.. naja dann liest er wo noch nicht geschrieben ist!
deshalb ist das mit dem extra thread, naja ich sag mal "Festplattenabhängig"..
ich hatte vor, 1 Block IMMER im Arbeitsspeicher behalten (geht von Zahl 1 bis 8 Mrd), da hier die Zahlen sind, deren vielfaches gestrichen wird... die blöcke in denen gestrichen wird, würde ich dann "hin und her" schieben.. wahrscheinlich würde ich sogar ERST den kompletten 2ten block berechnen, block 2 auf Festplatte schieben, block 3 rausholen, kompletten block 3 machen, block 3 auf Festplatte schieben, block 4 holen....
Ich denke das sollte klappen  Dann wären Berechnungen bis (8Mrd)² möglich! (die vorherigen (4Mrd)² wurden verdoppelt, da ich nur noch ungerade zahlen in dem bit-boolean Array habe !
Nachtrag 1: oder glaubst du der liest/schreibt schnell genung, dass ich direkt das vielfache von PrimX bis zum letzten Block "in einem Wisch" ausstreichen kann?
Nachtrag : Nach genauerem Anschauen deines Code verstehe ich eine Zeile nicht:
Delphi-Quelltext 1:
| for Schleife := 1 to 80000 do |
klar, das ist die Schleife in der du den DatenBlock auf die Festplatte (in den Stream) schreibst, aber warum nur bis 80000?
ebenso verstehe ich den sinn von deiner Variable ZahlByte nicht...
P.S:
Delphi-Quelltext 1:
| DatenBlock[Schleife] := $55; |
würde jede gerade zahl auf true setzten^^ (vorrausgesetzt man beginnt mit 1 (der ersten natürlichen positiven zahl, die also in der lage sei eine Primzahl zu sein)
Nachtrag 3 (solangsam sollte ich erst alle fragen überlegen  ): Ich würde gerne in die 1 "Zeile" bzw. an anfang die Größe des Arrays schreiben!, da der letzte block nicht immer aus 4 Mrd Bits besteht (bei der Berechnung bis 20 Mrd bestehen Block 1 und 2 aus je 4Mrd und Block 3 aus 2 Mrd Bits)...
und da ich ja mehrere blöcke nach "hinten" versetzte, sollte ich dann ein Array of TFileStream anlegen?
und auslesen geht mit (wenn ich die Arraylänge aus der ersten zeile bereits kenne womit? .. bitte schreibe mir die "schreib" und "lese" schleifen einmal als Beispiel  ...
ich denke es muss
Delphi-Quelltext 1: 2:
| For Schleife:=1 to High(DatenBlock) do FS.WriteBuffer(DatenBlock[Schleife], SizeOf(DatenBlock[Schleife]); | sein... und mir ist eingefallen, ich könnte die "größe des Arrays" ja auch als Int64 Zahl zusammen mit dem Pfad einfach abspeichern, dann muss dass nicht mit in die Datei rein..
lesen geht mit:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
|
setlength(DatenBlock, Gesp[BlockNr].Anzahl); For Schleife:=High(DatenBlock) downto 1 do FS.ReadBuffer(DatenBlock[Schleife], SizeOf(DatenBlock[Schleife])); |
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: Do 25.04.13 01:00
IhopeonlyReader hat folgendes geschrieben : | weißt du wie lange das ca dauert, bis 0,5 Gb geschrieben/gelesen sind? |
40 GB in etwa 8 Minuten inklusive der Initialisierung. Das Schreiben und Lesen geht wirklich sehr schnell, nur das Initialisieren des Datenblocks dauert etwas. Das hängt aber von der Größe ab. Da kannst Du bei der Größe ruhig etwas experimentieren.
Zitat: | weil wenn ich das in ein extra thread packe, und der dann mit der Berechnung schneller ist, als mit dem schreiben.. naja dann liest er wo noch nicht geschrieben ist! |
Ich meinte alles in einen Thread auslagern. Also beginnend ab FileStream.Create, dem Initialisieren des Datenblocks, das Schreiben der Datenblocks bis zur gewünschten Dateigröße, das Sieben usw.
Zitat: | ich hatte vor, 1 Block IMMER im Arbeitsspeicher behalten (geht von Zahl 1 bis 8 Mrd), da hier die Zahlen sind, deren vielfaches gestrichen wird... die blöcke in denen gestrichen wird, würde ich dann "hin und her" schieben.. wahrscheinlich würde ich sogar ERST den kompletten 2ten block berechnen, block 2 auf Festplatte schieben, block 3 rausholen, kompletten block 3 machen, block 3 auf Festplatte schieben, block 4 holen....
Ich denke das sollte klappen Dann wären Berechnungen bis (8Mrd)² möglich! (die vorherigen (4Mrd)² wurden verdoppelt, da ich nur noch ungerade zahlen in dem bit-boolean Array habe ! |
Zitat: | klar, das ist die Schleife in der du den DatenBlock auf die Festplatte (in den Stream) schreibst, aber warum nur bis 80000?
ebenso verstehe ich den sinn von deiner Variable ZahlByte nicht... |
Ich habe einfach diesen Wert genommen, um beim Testen nicht jedes Mal minutenlang warten zu müssen. Einfach den Wert erhöhen, und Du hast eine größere Datei. ZahlByte ist einfach der Name für eine Byte-Variable. Wegen der Endian-Speicherung würde ich Dir dringend empfehlen, hier mit Bytes zu arbeiten, sonst schaffst Du Dir hier unnötig Probleme. Siehe im Beispiel "Zahl := $12345678;". Da schreibe ich eine Zahl (= 4 Bytes).
Zitat: |
Delphi-Quelltext 1:
| DatenBlock[Schleife] := $55; |
würde jede gerade zahl auf true setzten^^ (vorrausgesetzt man beginnt mit 1 (der ersten natürlichen positiven zahl, die also in der lage sei eine Primzahl zu sein) |
Nein. Lese mal die Bits von rechts nach links. Mit $55 werden alle Bits gesetzt (01 01 01 01), die den ungeraden Zahlen entsprechen sollen. Zum Schluss schieße ich im ersten Byte der Datei die Bits um, weil 1 keine Primzahl ist, 2 aber doch. Dann steht dort $56 (01 01 01 10). Immer daran denken, es wird von rechts nach links gelesen.
Um es noch einmal zu verdeutlichen, wie das funktionieren soll:
Jedes Byte repräsentiert 8 Zahlen. Im ersten Byte stehen die Bits (immer von rechts nach links lesen) für die Zahlen 8 7 6 5 4 3 2 1.
Für die z. B. ersten drei Bytes stehen die Bits für folgende Zahlen: 8 7 6 5 4 3 2 1 *** 16 15 14 13 12 11 10 9 *** 24 23 22 21 20 19 18 17.
Zitat: | Ich würde gerne in die 1 "Zeile" bzw. an anfang die Größe des Arrays schreiben!, da der letzte block nicht immer aus 4 Mrd Bits besteht (bei der Berechnung bis 20 Mrd bestehen Block 1 und 2 aus je 4Mrd und Block 3 aus 2 Mrd Bits)... |
Wozu? Du kennst die Dateigröße bzw. kannst die abfragen. Da jedes Byte 8 Zahlen entspricht, kennst Du auch den Maximalwert dafür.
Zitat: | und da ich ja mehrere blöcke nach "hinten" versetzte, sollte ich dann ein Array of TFileStream anlegen? |
TFileStream ist eine nicht visuelle Komponente zum Schreiben und Lesen von Dateien. Wenn Du vier Leute nacheinander anrufen möchtest, schaffst Du Dir ja auch nicht extra dafür vier Telefone an.
Zitat: | und auslesen geht mit (wenn ich die Arraylänge aus der ersten zeile bereits kenne womit? .. bitte schreibe mir die "schreib" und "lese" schleifen einmal als Beispiel ...
ich denke es muss
Delphi-Quelltext 1: 2:
| For Schleife:=1 to High(DatenBlock) do FS.WriteBuffer(DatenBlock[Schleife], SizeOf(DatenBlock[Schleife]); | sein... und mir ist eingefallen, ich könnte die "größe des Arrays" ja auch als Int64 Zahl zusammen mit dem Pfad einfach abspeichern, dann muss dass nicht mit in die Datei rein..
lesen geht mit:
Delphi-Quelltext |
Wozu???
Zitat: | Delphi-Quelltext 1: 2: 3:
| setlength(DatenBlock, Gesp[BlockNr].Anzahl); For Schleife:=High(DatenBlock) downto 1 do FS.ReadBuffer(DatenBlock[Schleife], SizeOf(DatenBlock[Schleife])); | |
In meinem Beispiel verwende ich kein ReadBuffer und auch kein WriteBuffer. Gelesen wird, in dem man FileStream.Position auf das Byte vor den zu lesenden oder zu schreibenden Bereich setzt und dann mit FileStream.Write bzw. Read den Bereich schreibt oder liest. Man kann ein einzelnes Byte ansprechen (siehe ZahlByte im Beispiel), ein Word, ein Integer, ein Int64, ein Array of irgendwas oder sonst was lesen und schreiben. ABER: Das Sieb des Erastothenes funktioniert hier nur, wenn die Bits geordnet in der Datei vorliegen. Mit Integer oder Int64 auf das Datenmaterial in der Datei zuzugreifen ist tödlich, weil beim Speichern die Bytereihenfolge auf der Festplatte geändert wird (siehe: de.wikipedia.org/wiki/Byte-Reihenfolge). Aus $12345678 wird dann ein $78563412 auf der Platte. Führe mein Beispiel mal unverändert aus und schaue Dir dann die Datei im Hex-Editor an. Greift man dann auf die Daten mit Read(ZahlByte, SizeOf(ZahlByte)) zu, handelst Du Dir falsche Werte bei der nachfolgenden Bearbeitung ein. Ein "$55 xor $03" macht mit den Daten etwas anderes als ein "$55555555 xor $03". Teste es aus!
|
|
GuaAck
      
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: Do 25.04.13 20:15
Vielleicht liest es ja noch jemand:
Zumindest wenn das RAM voll ist und die Auslagerungsdatei gebraucht wird, dann ist auch Kompression eine Option. Kompression/Dekrompession kann viel schneller sein als I/O von der Festplatte.
Leider hängt es von der Datenart und der Abstimmung zwischen Kompressionverfahren und Datenart ab, was man gewinnt (und ob überhaupt). Zum Vergleich: ZIP reduziert die Größe der meisten üblichen Dateitypen ganz grob geschätzt um den Faktor 2, bei einigen Dateitypen bringt es praktisch nichts, gelegentlich bringt es auch dramatisch mehr. (Test mit einem Zipper: 1 MB mit Nullen wird auf ca. 1 kB komprimiert, 1 MB mit Zufallszahlen wird sogar um wenige Bytes größer. Kein überraschendes Ergebnis, zeigt aber schön den Effekt).
Ich würde damit anfangen, einen Testdatensatz zu zippen, das gibt schon ein Indiz. Evtl. es auch einmal mit anderen Kompressionverfahren zu versuchen.
Wenn da keine Kompression erreicht werden kann, dann würde ich dann Ansatz vergessen, auch wenn theoretisch was möglich wäre.
Gruß
GuaAck
|
|
IhopeonlyReader 
      
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: So 28.04.13 14:30
Gerd Kayser hat folgendes geschrieben : |
Zitat: | und da ich ja mehrere blöcke nach "hinten" versetzte, sollte ich dann ein Array of TFileStream anlegen? |
TFileStream ist eine nicht visuelle Komponente zum Schreiben und Lesen von Dateien. Wenn Du vier Leute nacheinander anrufen möchtest, schaffst Du Dir ja auch nicht extra dafür vier Telefone an. |
habe ich beachtet  es gibt nun ein "speicher" und Lade- "thread"... denn wenn er z.B. mit block 3 fertig ist, muss 3 ja nach hinten geschoben werden und block 5 schonmal geladen werden... dann rechnet wer mit block 4, danach schiebt er block 4 nach hinten und holt 6 schomal hervor ...
Gerd Kayser hat folgendes geschrieben : |
In meinem Beispiel verwende ich kein ReadBuffer und auch kein WriteBuffer. Gelesen wird, in dem man FileStream.Position auf das Byte vor den zu lesenden oder zu schreibenden Bereich setzt und dann mit FileStream.Write bzw. Read den Bereich schreibt oder liest. Man kann ein einzelnes Byte ansprechen (siehe ZahlByte im Beispiel), ein Word, ein Integer, ein Int64, ein Array of irgendwas oder sonst was lesen und schreiben. ABER: Das Sieb des Erastothenes funktioniert hier nur, wenn die Bits geordnet in der Datei vorliegen. Mit Integer oder Int64 auf das Datenmaterial in der Datei zuzugreifen ist tödlich, weil beim Speichern die Bytereihenfolge auf der Festplatte geändert wird (siehe: de.wikipedia.org/wiki/Byte-Reihenfolge). Aus $12345678 wird dann ein $78563412 auf der Platte. Führe mein Beispiel mal unverändert aus und schaue Dir dann die Datei im Hex-Editor an. Greift man dann auf die Daten mit Read(ZahlByte, SizeOf(ZahlByte)) zu, handelst Du Dir falsche Werte bei der nachfolgenden Bearbeitung ein. Ein "$55 xor $03" macht mit den Daten etwas anderes als ein "$55555555 xor $03". Teste es aus! |
ok, ich "benutzte" zwar Bit-Booleans, aber zur Auslagerung lagere ich die Bytes (mit je 8 Bit-Booleans) aus.. ich denke das ist schneller, daher ist es mit BUFFER dann doch richtig oder?.. ich wird mal beides ausprobieren
GuaAck hat folgendes geschrieben : | Vielleicht liest es ja noch jemand: |
Ja^^
GuaAck hat folgendes geschrieben : |
Zumindest wenn das RAM voll ist und die Auslagerungsdatei gebraucht wird, dann ist auch Kompression eine Option. Kompression/Dekrompession kann viel schneller sein als I/O von der Festplatte.
|
naja, zumindest beim "ersten" auslagern wird dies sicherlich SEHR nützlich sein, da hier ja alle noch auf True (1) sind..
Allerdings: ich denke ich werde es zwar auslagern, aber die "späteren" Blöcke nicht auslagern, sondern erst später erstellen..
Bsp. während Block 1 Berechnet wird, wird Block 2 erstellt.
Danach wird Block 1 gespeichert (aber nicht freigeben, da hierraus die vielfachen ja noch gestrichen werden), block 2 wird "errechnet" und block 3 wird erstellt..
Danach wird Block 2 ausgelagert, block 3 berechnet und block 4 erstellt...
Nachtrag:
Zitat: | Wozu? Du kennst die Dateigröße bzw. kannst die abfragen. Da jedes Byte 8 Zahlen entspricht, kennst Du auch den Maximalwert dafür. |
Nicht ganz, es gibt eine "Mindestgröße" für eine Datei (zumindest bei Windows).. wenn ich Primzahlen bis 4Mrd + 10 berechne, dann ist die 2teAuslagerungsdatei > 10 Bits!
ich glaube unter Windows kann man die "Mindestgröße" im Bereich "schnell"/"speichernutzung" der Festplatte einstellen.. sie beträgt zwischen 104 B und 4096 B/ 4KB soviel ich weiß.. daher ist dies nicht immer möglich (meine Mindestgröße liegt bei 1 KB)
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: So 28.04.13 16:58
IhopeonlyReader hat folgendes geschrieben : | Nicht ganz, es gibt eine "Mindestgröße" für eine Datei (zumindest bei Windows).. wenn ich Primzahlen bis 4Mrd + 10 berechne, dann ist die 2teAuslagerungsdatei > 10 Bits!
ich glaube unter Windows kann man die "Mindestgröße" im Bereich "schnell"/"speichernutzung" der Festplatte einstellen.. sie beträgt zwischen 104 B und 4096 B/ 4KB soviel ich weiß.. daher ist dies nicht immer möglich (meine Mindestgröße liegt bei 1 KB) |
Da verwechselst Du was. Die Dateigröße und die Größe des belegten Festplattenspeichers sind zwei Paar Schuhe. Was der Windowsexplorer anzeigt, ist wieder etwas anderes.
Die Dateigröße (die man abfragen kann) gibt die Byte-genaue Größe der Datei an. Der belegte Festplattenspeicher ist etwas größer, weil für eine Datei größer 0 Bytes immer mindestens ein ganzer Cluster (besteht aus mehreren Sektoren) belegt wird. Und der Windowsexplorer kennt nur 0 Bytes oder mindestens 1 KB.
Einloggen, um Attachments anzusehen!
|
|
IhopeonlyReader 
      
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: Mo 29.04.13 20:51
ok stimmt natürlich Gerd...
ich habe mir überlegt, dass es ja sinnlos wäre die fertig initialisierten Bits, die am Anfang noch 1 (True) sind, auszulagern.. dafür, wie das gehen wird, danke ich dir noch einmal Gerd Kayser . ich werde aus "übungsgründen" später noch einmal mit "Auslagerung" umsetzen.
Jetzt erstelle ich die Blöcke erst, wenn sie benötigt werden, nach der Berechnung werden sie gespeichert und danach gelöscht...
zur Zeit berechne ich die Primzahlen bis 100 Mrd.. mal schauen wie lange er ca. pro block braucht
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
Mr_Emre_D
      
Beiträge: 114
Erhaltene Danke: 14
|
Verfasst: Mi 08.05.13 22:08
Mal ne Frage - ging es hier eig. ausschließlich darum, Boolean Arrays kleiner zu kriegen oder eher darum, möglichst viele / große Primzahlen zu berechnen (mit Delphi-Hausmitteln)?
Falls es ums zweitere ging:
Man benötigt kein großes Array, es reicht vollkommen ein z.B. 1024 Byte großes Array herzunehmen.
Man fängt wie gewohnt bei 1 an, wendet den Siebalgo an und hat einmal alle Primzahlen von 1..1024 ermittelt.
Als nächstes verschiebt man das Array um +1024; die Dimension des Arrays ändert sich nicht, jedoch ist Array[0] = die Zahl 1024!
Dh. man wendet den Siebalgo nochmal an - natürlich rechnet man jz nicht per Addition hoch bis man bei 1024 angelangt ist,
sondern macht einfach eine Division, rundet ab und multipliziert dann mit dem Faktor und schon ist man direkt vor 1024.
Dann wie gewohnt addieren und Vielfache eleminieren. Natürlich index anpassen (-1024 rechnen).
Somit kann man Stück für Stück immer 1024 (meinetwegen auch mehr) berechnen.
Die Grenze ist dann für Delphi Int64 (2^64)
Das ganze dürfte dann natürlich dauern!
Demo folgt sofern mir die Lust nicht vergeht!
Edit: Der Nachteil ist jedoch, dass man trotzdem jedesmal wieder die Vielfachen von Anfang an eleminieren muss.
Dafür ist man halt das Problem mit dem Speicher los. Man muss halt abwägen..
Zuletzt bearbeitet von Mr_Emre_D am Mi 08.05.13 23:46, insgesamt 1-mal bearbeitet
|
|
Mr_Emre_D
      
Beiträge: 114
Erhaltene Danke: 14
|
Verfasst: Mi 08.05.13 23:39
Habs grad implementiert und direkt getestet.
Als ByteBooleanArray Größe habe ich 1 mb genommen (1024 * 1024). Dh ich berechne zuerst die Primzahlen
[3, 1024*1024], dann
[3 + 1024*1024, 3 + 1024*1024*2], anschließend
[3 + 1024*1024*2, 3 + 1024*1024*3] usw usf.
Allgemein
[3 + 1024*1024*x, 3 + 1024*1024*(x+1)]
Habe grad bis 4096 iteriert (das sind dann 4096 * 1024*1024 = 4 gb).
Auf meinem Rechner hat es 218.92 Sekunden gedauert und eine Blockberechnung (1mb) hat im Schnitt 55 Ticks gedauert.
Auf die Ausgabe habe ich verzichtet, wer mag, kann es ausgeben lassen bzw. den Code so ändern, dass die Ausgabe gespeichert wird.
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: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133:
| program LOP;
{$APPTYPE CONSOLE}
uses Windows;
type TByteBoolean = record Value: Byte; function GetBit(const Index: Integer): Boolean; procedure SetBit(const Index: Integer; const Bit: Boolean); end;
TByteBooleanArray = Array of TByteBoolean;
{$REGION 'TByteBoolean'}
function TByteBoolean.GetBit(const Index: Integer): Boolean; begin Result := Value and (1 shl Index) <> 0; end;
procedure TByteBoolean.SetBit(const Index: Integer; const Bit: Boolean); begin if Bit then Value := Value or (1 shl Index) else Value := Value and not (1 shl Index); end;
{$ENDREGION}
procedure ExtendedSieveOfEratosthenes(const FromOffset: UInt64; var Primes: TByteBooleanArray); var ToOffset : UInt64; candidate : UInt64; multiples : UInt64; index : Integer; begin candidate := 3; ToOffset := FromOffset + Length(Primes) shl 4; while candidate < ToOffset do begin if candidate < FromOffset then begin multiples := candidate * Round(FromOffset/candidate); if multiples < FromOffset then inc(multiples, candidate); end else multiples := candidate shl 1;
if multiples > ToOffset then break;
while multiples <= ToOffset do begin if multiples and 1 = 1 then begin index := (multiples - FromOffset) shr 1; Primes[index shr 3].SetBit(index mod 8, false); end; inc(multiples, candidate); end;
inc(candidate, 2); end; end;
var Primes: TByteBooleanArray; iteration: Integer; p, q: Integer; From: UInt64; Tick: DWORD; Duration: DWORD; Til: UInt64; PrimeCount: UInt64; ptr: PDWord; cnt4: DWord;
begin SetLength(Primes, 1024*1024 shr 4); From := 3; Til := 1000000000; Til := Til * 12; iteration := 0; PrimeCount := 0; Duration := GetTickCount; cnt4 := Length(Primes) div 4; while From < Til do begin inc(iteration); ptr := @Primes[0]; for p := 0 to cnt4 do begin ptr^ := $FFFFFFFF; inc(ptr); end; ExtendedSieveOfEratosthenes(From, Primes); for p := 0 to High(Primes) do for q := 0 to 7 do if Primes[p].GetBit(q) then begin if (From + (p*8 + q)*2) < Til then inc(PrimeCount); end; if iteration mod 100 = 0 then Write('[Iteration #', iteration, '] calculated primes [', From, ', ', From + Length(Primes) shl 1, '] (time: ', (GetTickCount-Duration)/1000:6:2, ')'#13); inc(From, Length(Primes) shl 4); end; Duration := GetTickCount - Duration;
Writeln('Finished, took me ', Duration/1000:8:2, ' seconds... '); Writeln('Found ', PrimeCount, ' primes'); Readln; end. |
Zuletzt bearbeitet von Mr_Emre_D am Do 09.05.13 03:13, insgesamt 6-mal bearbeitet
|
|
Mathematiker
      
Beiträge: 2622
Erhaltene Danke: 1448
Win 7, 8.1, 10
Delphi 5, 7, 10.1
|
Verfasst: Mi 08.05.13 23:48
Hallo,
Mr_Emre_D hat folgendes geschrieben : | Habe grad bis 4096 iteriert (das sind dann 4096 * 1024*1024 = 4 gb).
Auf meinem Rechner hat es 218.92 Sekunden gedauert und eine Blockberechnung (1mb) hat im Schnitt 55 Ticks gedauert. |
Ich will Dich ja nicht ärgern, aber Dein Verfahren hat Horst_H schon in mehreren Threads zu Primzahlen beschrieben.
Bei meiner Suche nach einsamen Primzahlen www.entwickler-ecke....ewtopic.php?t=111471 dauert das Sieben (+ Auswertung und die kostet Zeit) von 4 Milliarden Primzahlen auf meinem alten PC nur 28 Sekunden.
Beste Grüße
Mathematiker
_________________ Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
|
|
Mr_Emre_D
      
Beiträge: 114
Erhaltene Danke: 14
|
Verfasst: Mi 08.05.13 23:51
Das ärgert mich nicht.
Wie bereits zuvor schon geschrieben, war mir klar, dass diese Variante nicht schnell(er) ist, dafür hat sie aber das Problem mit dem Speicher nicht.
Und darum ging es hier doch, bei diesem Thread, nicht?
|
|
Mr_Emre_D
      
Beiträge: 114
Erhaltene Danke: 14
|
Verfasst: Do 09.05.13 01:59
|
|
IhopeonlyReader 
      
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: Do 09.05.13 13:56
hättest du den ganzen Thread mitverfolgt, wüsstest du dass ich das bereits mache
ich berechne 1 block (bei mir ist 1 block 4 mrd booleans groß) und danach den nächsten und so weiter....
ich brauche für Primzahlen bis 4 Mrd ca 120 sek und mein Programm ist (wenn es voll rechnet, also 3x 4mrd booleans im speicher hat (1x unterste4n Primzahlen deren vielfaches in block X weggestrichen werden und der fertige block der abgespeichert wird) kleiner als 1 GB (928 MB) im Arbeitsspeicher (ram)
berechne ich ohne "arbeitsspeicherplatzsparung" schaffe ich die zahlen bis 4 mrd leider nicht, da Delphi nur bis 1,5 gb ram nutzen kann.. bis 1 mrd brauch ich ohne sparung 15 sek
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
Mr_Emre_D
      
Beiträge: 114
Erhaltene Danke: 14
|
Verfasst: Do 09.05.13 15:24
Ich bin eigentlich über den ganzen Thread drübergeflogen (hab mir halt nur die Sourcen nicht angescahut)..
Falls dir das eh eingefallen ist, nvm!
|
|
Boldar
      
Beiträge: 1555
Erhaltene Danke: 70
Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
|
Verfasst: Do 09.05.13 20:51
Zur Auslagerung auf die HDD sollte man evtl. MMF's verwenden.
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Fr 10.05.13 11:38
Hallo,
was will man mit den ganzen Zahlen auf der Festplatte?
Kleinere Abschnitte zu Bearbeiten ist von großem Vorteil, es geht einfach viel schneller, weil der Speicherzugriff beim Sieben über große Distanzen erfolgt und damit langsam ist.
120 Sekunden für 4 Milliarden ist nicht überaus schnell.
SegSiebTest.pas benötigt bei mir ca 10 Sekunden und kann bis 2.6e11 Sieben.Die unit mp_prime ist von Gammatester aus mparith.
Diese habe ich nur aus Bequemlichkeit drin.Natürlich kann ich mit dem eigenen Sieb selbst die Zahlen ersieben.
Viel Interessanter wäre doch, von Kim Walisch die C++ object Datei einbinden zu können-> Die Summe der ersten 1e9 Primzahlen ( bis 22.801.929.150 zu sieben ) in 10 Sekunden.
Mein Programm braucht schon über 60 Sekunden für das sieben ( Ok: Addieren geht fast unbemerkt unter ) und circa 5.7 Mb Platz, davon 5 Mb für die Primzahlen.
Quelltext 1: 2: 3: 4:
| Hoechste Primzahl 510529 Siebe ab 0 Gesiebt bis 22801929150 1.000.006.971 real 1m1.053s |
Es siebt und zählt immer vollständige Siebe a 510510 Elemente, deshalb sind es 6.971 mehr.
Es lohnt sich nicht, die Festplatte zu quälen
Gruß Horst
Für diesen Beitrag haben gedankt: Mathematiker
|
|
|