Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Riesige Boolean-Array verkleinern?
IhopeonlyReader - So 14.04.13 13:59
Titel: Riesige Boolean-Array verkleinern?
Guten Tag, ist es möglich ein dynamisches Array von 1..x mit x>2Milliarden zu erstellen? (Vom Typ Boolean)
also
var DasArray: Array of Boolean;
und dann
setlength(DasArray, 10000000000);// (10milliarden)
oder muss man dann ein 2D Array erstellen, dass je 1 bzw. 2 Millarde groß ist?
also
var DasArray: Array of Array of Boolean;
setlength(DasArray, ceil(10000000000/1000000000), 1000000000); //ceilceil(10000000000/1000000000)=10
Edit: und was ist wenn man ein Array > (2Millarden)² haben will? Muss man dann ein 3D Array anlegen?
und wenn ja, wie kann man direkt ein "unbegrenztes Array" erzeugen?
Edit2: Und wenn es möglich ist ein unendliches Array zu haben, geht dieses bei 4 Milliarden schon über die meisten Arbeitsspeicher hinnaus... ist es also möglich diese auf der Festplatte auszulagern? (wenn auch nur für wenige Sekunden)
Edit vom 16.04: Titel von "Unendliches Array möglich" in "Riesige Boolean-Array verkleinern" umgeschrieben
MeierZwoo - So 14.04.13 15:39
1. Unendlich geht nicht, weil unendlich als real nicht erreichbar definiert ist.
2. Jedes dynamische Array ist erstmal per Definitition unbegrenzt (allerding in den Grenzen des Endlichen)
3. Wenn eine Speicherbelegung den RAM überschreitet, wird eh (auf Platte) ausgelagert - auch schon vorher, weil ja noch etwas mehr im RAM ist als nur die eine Variable
4. kann man selbst ein Array so verwalten, daß es größer als der RAM ist - siehe früher bei Variablen > Segment.
5. Bloß wozu das? Bei solchen riesen Variablen lagert man gleich in eine db aus.
Delphi-Laie - So 14.04.13 15:52
IhopeonlyReader hat folgendes geschrieben : |
Guten Tag, ist es möglich ein dynamisches Array von 1..x mit x>2Milliarden zu erstellen? (Vom Typ Boolean) [...] |
Solche Fragen zu beantworten ist Delphi selbst der kompetenteste Antwortgeber.
IhopeonlyReader - So 14.04.13 15:55
1. Danke also kein 1D Array ist als "unendliches Array" möglich
2. Logisch :D also begrenzt
3. Werde ich dann ausprobieren, ob ich auch mehr als 5 Milliarden Booleans (ca. 5 Milliarden Bit = ca. 4,66 GB benötigt) erzeugen kann :D (bei 4 GB Ram)
4. siehe 3.
5. db = database? dann werde ich
http://www.delphi-treff.de/tutorials/datenbanken/interbase/erstellen-der-client-anwendung-mit-delphi/ mal durchgehen
Edit: @Delphi-Laie: Ich meine damit, ob es möglich ist (wie durch ein 2D Array) das eigentliche Maximum zu übergehen...
Lösungsvorschlag:
type
TUnendlichesArray = class
NochGroesser: Array of TUnendlichesArray;
IntergerVar: Array of Integer;
end;
Und dann für ceil(X/MaxArray) das UendlichArray um 1 Array erhöhen... Wäre das Möglich?
Delphi-Laie - So 14.04.13 16:08
Zum Indizieren der Arrayelemente werden integre Datentypen verwandt - diese können schließlich auch nicht unendlich groß sein.
Gerd Kayser - So 14.04.13 16:15
Ich würde ein Array of Integer wählen. Dann kommt man mit einem Bruchteil des Speichers aus. Man kann ja sagen, dass ein gesetztes Bit true, ein nicht gesetztes Bit false entsprechen soll. Ein Integer ist 32 Bit groß und kann somit 32 verschiedene Bit-Werte speichern. Es ist allerdings ein wenig Rechnerei erforderlich, um z. B. das 20.000ste Bit anzusprechen.
Siehe auch
http://www.delphipraxis.net/55716-warum-ist-ein-boolean-so-gross.html zum Platzbedarf.
IhopeonlyReader - So 14.04.13 16:20
Geht Round(ExtendedVar) nicht als Indexangabe?
Edit:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| var Test: Array of Integer; T: Extended; begin T := 0; Setlength(Test, 10); Showmessage( IntToStr(Test[ Round(T) ]) ); end; |
funktioniert bei mir wunderbar
Jann1k - So 14.04.13 17:02
Wäre gut, wenn du uns mitteilst wofür du denn das Riesenarray eigentlich nutzen willst, 2+ Milliarden Einträge schreit nach Designfehler oder DB.
Gausi - So 14.04.13 17:11
Laut Profil Delphi 7, also auf jeden Fall eine 32-Bit-Anwendung. Also ist die Größe des verfügbaren Speichers für die Anwendung auf 2GB beschränkt (mit Tricks auch 3, iirc). Da kannst du dir 128 TB RAM in den Rechner packen, deine Delphi-Anwendung kommt über die 2GB nicht hinaus.
Da ein Array auch zusammenhängend im Speicher liegen muss, ist in der Regel bei ~1.5GB Schluss.
IhopeonlyReader - So 14.04.13 21:23
Gausi hat folgendes geschrieben : |
Laut Profil Delphi 7 |
Richtig :)
Gausi hat folgendes geschrieben : |
Da ein Array auch zusammenhängend im Speicher liegen muss, ist in der Regel bei ~1.5GB Schluss. |
Das habe ich auch schon gemerkt.. 1.587.604 KB (also 1.515 GB) ist Ende... mehr kriege ich nicht hin :(
Und wie wäre es möglich mehr als diese 1,5 GB zu nutzen? (du erwähntest "mit Tricks auch 3").. diese 3 würde ich gerne voll nutzen :)
Gausi - So 14.04.13 21:39
Näheres dazu weiß ich nicht...wie man das hinbekommt, weiß ich nicht. Es bleibt aber immer noch das Problem, dass das Array zusammenhängend im Speicher liegen muss. Das ist ein zusätzliches Problem.
Mein Tipp: Konzept ändern oder auf 64 Bit wechseln.
Edit: Oder den Hinweis von Gerd Kayser umsetzen.
Delete - Mo 15.04.13 00:00
Erzähl doch mal, was du eigentlich damit vor hast. Sicher findet sich dann eine gangbare Möglichkeit. Schließlich wurdest du jetzt schon dreimal danach gefragt und bist die Antwort schuldig geblieben.
Tranx - Mo 15.04.13 05:46
Und eines ist sicher:
Nimmt man Deinen Titel, so ist die Frage wohl nur rhetorisch.
Ein unendlich großes Array ist definitiv nicht nur wegen der zu kleinen Integer-Größe der Indizierung, sondern wegen des viel zu kleinen Speicherplatzes selbst aller Rechner dieser Erde nicht möglich. Du könntest selbst alle Computer oder was auch immer des Universums zusammenschalten und dann wärst Du nicht mal bei 0,000000000001% des Wertes für unendlich.
Was ich damit sagen will: Es gibt nichts im Universum, was unendlich ist, also erst Recht nichts auf dieser viel kleineren Erde. Unendlich ist bloß ein Konstrukt, um etwas darzustellen, was es nicht gibt: 1/0.
Und dann ist das, was Du im Text fragst, was ganz anderes, als das, was Du im Titel schreibst.
Und ich denke schon, dass das möglich ist, aber sicher - wenn Du ein so großes Array überhaupt nutzen willst, schon fast etwas für Datenbankanwendugnen. Da aber wenig über den Zweck des Ganzen klar ist, kann man nur spekulieren, und das ist wenig sinnvoll.
IhopeonlyReader - Mo 15.04.13 15:33
Allgemein: Booleans zusammenfassen um Speicher zu sparen (Ram)
Genaues Beispiel: Zur Zeit Sieb des Eratosthenes... wenn ich Primzahlen bis 2 Milliarden errechnen will, so erstellt er ein Array bis 2Milliarden (zur Zeit ca 1,7GB Groß [2 Millarden Byte])... allerdings hat Gerd Kayser mich daran erinnert, das Booleans (true, False) eigentlich nur 2 Werte speichern -> 1Bit aber um schneller zu sein 8 Bit (1Byte) groß sind.. (0-255) hierbei enspricht 0= True 1-255 = False...
Meine Überlegung:
Ein Array of Byte anzulegen und dieses nur 1/8 mal so groß zu gestalten wie das voherige Boolean-Array...
Dann gäbe es eine Procedure SetzteBoolean(Zahl: Integer; Wert: Boolean);
Das aus floor(ln(Zahl)/ln(2)) ausrechnet, in welchem Byte es stehen müsste, und dann mit
Function GibBoolen(Zahl: Integer): Boolean;
Result := power(2, ln(zahl) mod ln(2))>=Byte[floor(ln(Zahl)/ln(2))] //wenn es eintrifft dann ist die Zahl (Boolean) = True, sonst false..
wenn GibBoolean=Wert ist dann nichts machen sonst Byte[floor(ln(Zahl)/ln(2))] - power(2, ln(zahl) mod ln(2))
das ist alles eine theoretische Überlegung.. der Code ist jetzt einfach mal so aus dem Kopf... Aber ich denke er zeigt, wie in 8Bit 8Booleans gespeichert/ausgelesen werden können
.. Wenn ich Zeit habe, werde ich mein Sieb mal umprogrammieren
platzwart - Mo 15.04.13 15:37
Das geht doch viel einfacher... Einfach nur die Primzahlen, die man bis zur Zahl n gefunden hat, einem Array hinzufügen. Dann kann die Abfrage vereinfacht so ausschauen:
If ( zuTestendeZahl in primzahlArray) then istPrimzahl:= true else istPrimzahl:= false;
Dann brauchst du ja nur Einträge für die Primzahlen und du kannst einen wesentlich größeren Zahlenbereich abdecken.
IhopeonlyReader - Mo 15.04.13 15:50
@platztwart... bis zu der Zahl 1,5 Milliarden gibt es 74.726.528 Primzahlen(ca 75 Millionen)
also wäre das Integer Array (nach dem du verlangst) 75 Millionen* 32 (= 2,4 Milliarden) Bit groß..
das ist 1. wesentlich größer als 1*1,5Millarden Bit und würde somit MEHR Ram benötigen.. und
2. Wäre der Rechenaufwand für istPriemzahl := (zuTestendeZahl) in PrimzahlenArray)
soweit ich weiß ebenfalls größer -> dauert länger
Und 3. Das Sieb des Eratosthenes schließt zahlen aus! somit müsste man von Anfang an Ein Array mit ALLEN zahlen erzeugen, und dann zahl für zahl löschen.. das heißt dein Array wäre am Anfang 1,5Miliiarden*32Bit groß.. selbst wenn man die geraden zahlen am Anfang ausschließen würde (bis auf 2) wäre es noch (1,5Milliarden/2 +1) *32 (=1,2 Milliarden + 32) Bit groß
Edit: Eine Variante, die Zahl für Zahl durchgeht und einen Teiler sucht (bis Wurzel(Zahl)) habe ich auch schon programmiert, braucht aber ungefäht 100x so lange wie das Sieb
Edit 2: Der einzige Vorteil deiner Methode liegt darin, dass man jede einzelne Primzahl ausrechen würde, bei mir immer auf das nächste vielfache von 8.
so würdest du z.B. für Primzahlen Bis 9 am Anfang ein Array[1..9] of Integer anlegen und ich ein [1,..2] of Byte und würde damit sozusagen bis 16 die Primzahlen ausrechnen
Gammatester - Mo 15.04.13 16:04
Wenn Du mit einfacher "platzsparender" meinst, dann ist das eine Milchmädchen-Rechnung: Es gibt 105097565 Primzahlen <= MaxLongint, diese verbrauchen 4*105097565 = 420390260 Bytes in einem Array of longint. Speichert man als Bitmuster braucht man naiv 268435455 Bytes (also schon mal weniger); da aber alle Primzahlen bis auf eine ungerade sind, kommt man mit der Hälfte = MaxLongint div 16 = 134217727 aus, also mit ca 32% des Primzahlarrays.
platzwart - Mo 15.04.13 16:30
Du sprichst ja hier von "ins Unendliche". Dann mach die Rechnung mal mit 64-Bit Integer auf, dann schau das schon ganz anders aus... ;)
Gammatester - Mo 15.04.13 16:42
Aber nur wenn Du mir verrätst, wie Du die ca 425656284014012096 64-Bit Primzahlen in ein Array packst. :wink:
Tranx - Mo 15.04.13 17:00
Vielleicht könnte man eine Menge Speicherplatz sparen, wenn man wie folgt speichert:
1: 1 1. Primzahl
2: 1 = 2 - 1
3: 1 = 3 - 2
4: 2 = 5 - 3
5: 2 = 7 - 5
6: 4 = 11 - 7
Also ab der 1. Primzahl (Meinetwegen kann es auch die 2 sein), nur noch die Differenz zwischen der vorherigen und der aktuellen Primzahl. Das werden selbst bei sehr hohen Primzahlen immer noch wesentlich kleinere Werte als die Primzahlen selber sein.
Dann kommt man möglicherweise schon mit Longint (4 Byte Integer) aus. Aber sicher wird die Grenze nur qweiter nach vorne geschoben.
Mathematiker - Mo 15.04.13 17:16
Hallo,
Tranx hat folgendes geschrieben : |
... nur noch die Differenz zwischen der vorherigen und der aktuellen Primzahl. Das werden selbst bei sehr hohen Primzahlen immer noch wesentlich kleinere Werte als die Primzahlen selber sein.
Dann kommt man möglicherweise schon mit Longint (4 Byte Integer) aus. |
Da ab der Primzahl 1425172824437699411 bis zur nächsten nur ein Abstand von 1476 auftritt, kannst Du auch smallint (2 Byte) für die Differenz verwenden.
Sicher gibt es zwei aufeinanderfolgende Primzahlen mit einem Abstand > 32767, aber die kleinste von denen ist nicht bekannt und wahrscheinlich sehr groß.
Eine schnelle bitorientierte Variante des Primzahlsiebs hat Fiete schon unter
http://www.entwickler-ecke.de/topic_Primzahlsieb+in+einer+BitVersion_108729.html veröffentlicht.
Beste Grüße
Mathematiker
IhopeonlyReader - Mo 15.04.13 17:45
ich rechne mit meinem Sieb schneller obwohl ich die geraden zahlen noch drin habe... allerdings arbeite ich immer noch mit 8 Bit- Booleans und ich denke nach der Umstellung werde ich zwar "weiter" rechnen können, das allerdings auf kosten der rechenzeit... ich werde es sehen.. denke morgen finde ich zeit dazu
IhopeonlyReader - Di 16.04.13 16:52
so ich habe das ganze nun umgesetzt.. ich brauche nun nur noch 1 Byte pro 8 Booleans + 40000MB an Arbeitsspeicher (vorher: 1Byte pro 1 Boolean + 4482 KB)
somit ist der Rechenaufwand ca 10x so groß und das zeigt sich in der Zeit... vorher: Primzahlen bis 1 Million in 0.016 sek.. jetzt nur noch 0.48 (ca 30x langsamer)
aber vielleicht findet ihr ja noch optimierungsvorschläge....
aus: //am Beispiel von 1 Million
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| var BoolArray: Array of Boolean;
setlength( BoolArray, 1000000 ); if BoolArray[X] then if BoolArray[X] then BoolArray[X] := False; |
Jetzt:
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: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40:
| var BitBoolArray : Array of Byte; const Size = 8; setlength( BitBoolArray , 1000000 div Size +1); if GibBoolean(X) then SetzteBool(X, False);
Function GibBoolean(Zahl: Integer): Boolean; var Z, CopyOfFeld: Byte; begin CopyOfFeld := BitBoolArray [Zahl div Size]; Result := False; For Z:=(Size-1) downto (Zahl mod Size) do if CopyOfFeld>=power(2, Z) then begin CopyOfFeld := CopyOfFeld - Round(power(2, Z)); Result := True; end else Result := False; end;
Procedure SetzteBoolean(Zahl: Integer; Wert: Boolean); begin if Wert then begin if not GibBoolean(Zahl) then BitBoolArray [Zahl div Size] := BitBoolArray [Zahl div Size] + round(power(2, (Zahl mod Size))); end else begin if GibBoolean(Zahl) then BitBoolArray [Zahl div Size] := BitBoolArray [Zahl div Size] - round(power(2, (Zahl mod Size))); end; end; |
Seht ihr verbesserungen?
Edit: Ein Vorteil, wo es mit Bytes schneller geht, ist die Initialiserung...
For C:=0 to High(BitBoolArray ) do BitBoolArray := 255; //X div 8 +1 Ausführungen power(2, Size)-1
vorher: For C := High(BoolArray) do BoolArray := True; //X ausführungen
jfheins - Di 16.04.13 18:14
Ja, jede Menge. Was hat zum Beispiel die Power-Funktion dort verloren, das geht doch auch mit bitweisen Operatoren?
So ungefähr:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| function GibBoolean(Zahl: Integer): Boolean; var Mask, CopyOfFeld: Byte; begin CopyOfFeld := BitBoolArray [Zahl div Size]; Mask = 1 shl (Zahl mod Size); Result := Boolean(CopyOfFeld and Mask); end;
procedure SetzeBoolean(Zahl: Integer; Wert: Boolean); var Mask, Index: Byte; begin Mask = 1 shl (Zahl mod Size); Index := Zahl div Size; if Wert then BitBoolArray[Index] := BitBoolArray [Index] or Mask; else BitBoolArray[Index] := BitBoolArray [Index] and not Mask; end; |
IhopeonlyReader - Di 16.04.13 18:51
Deine Methode klappt nicht ganz !
Ab Zahlen>2048 gibt es fehler ! ich weißt warum, aber ist so^^ bis zur Primzahl 2039 rechnet er richtig, danach ist für ihn jede zahl eine Primzahl (2048 auch schon)
jfheins - Di 16.04.13 21:23
Oh, ja Index darf natürlich kein Byte sein. Cardinal ist angebrachter.
Und übrigens ist der Typ des Arrays nicht leicht austauschbar, die Variablen Mask und CopyOfFeld müssen nämlich den gleichen Typen haben wie das Feld - das könnte man noch ändern ;-)
Mr_Emre_D - Mi 17.04.13 10:58
2 Milliarden Bits (Boolean: Delphi = 1 Byte (8 Bits), aber
eigentlich nur 2 Zustände, also reicht 1 Bit) =
2.000.000.000
In Byte = 2 Milliarden. / 8 = 250 000 000 = 250 Millionen. Byte
In KBytes = /1024 = 244140.625 KBytes
In MBytes = /1024 = 238.41 ~ 239 MB
Wenn du also wirklich nur Bits verwendest, benötigst du nur 239 MBytes.
Im Vergleich - wenn du Pro Boolean 8 Bits verwendest, ist das letzendlich das 8 fache von 239 MB
was = 1907.34 ~ 1908 mb wären ~ 2 GB
Falls es sich um ein sparse-Array handelt, lässt sich noch schön komprimieren (RLE+Huffman)
Aaaaber.. das alles ist nur ne Zahlenrumspieleri - im Grunde liegt hier
ein Design-fehler vor... Falls du eine Art BigInteger implementierst und somit große Zahlen brauchst,
tu das nicht auf Basis von Boolean und Boolean-Operatoren sondern nimm gleich 32 Bit (4 Byte - Integer/Cardinal) Blöcke..
Horst_H - Mi 17.04.13 13:01
Hallo,
man kann es auch mit set's lösen. Für 32 Bit Computer gehen 32 Bit am besten.
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: 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:
| program unbenannt; uses sysutils;
const BITPOS = 5; BITMASKE = 31;type tBoolSet = set of 0..BITMASKE; tBoolArr = Array of tBoolSet; var bA : tBoolArr;
function GibBoolean(Zahl: Integer): Boolean;inline; begin result:= (ZAHL AND BITMASKE) in bA[Zahl shr BITPOS]; end;
procedure SetzeBoolean(Zahl: Integer; Wert: Boolean); begin if Wert then include(bA[Zahl SHR BITPOS],Zahl AND BITMASKE) else exclude(bA[Zahl SHR BITPOS],Zahl AND BITMASKE); end;
const ArrBitSize = 100*1000*1000; ArrSize =(ArrBitSize+BITMASKE) SHR BITPOS; var T1,T0: TDatetime; i : LongInt;
BEGIN setlength(bA,ArrSize); T0 := now; For i:= 1 to ArrBitSize do SetzeBoolean(i,true); For i:= 1 to ArrBitSize do IF NOT(GibBoolean(i)) then writeln('Fehler bei: ',i);
For i:= 1 to ArrBitSize do SetzeBoolean(i,false); For i:= 1 to ArrBitSize do IF GibBoolean(i) then writeln('Fehler bei: ',i); T1 := now; Writeln( FormatDateTime('HH:NN:SSS.ZZZ',T1-T0)); setlength(bA,0); END. |
Ich habe extra keine Variable BitNr und Index eingebaut, weil es hier so extrem kurze Ausdrücke sind, die auch nur einmal verwendet werden, die braucht man nicht vor zu berechnen.
Da kann der Kompiler besser hantieren.
Gruß Horst
Mr_Emre_D - Mi 17.04.13 14:55
--Doppel
IhopeonlyReader - Mi 17.04.13 17:02
jfheins hat folgendes geschrieben : |
Oh, ja Index darf natürlich kein Byte sein. Cardinal ist angebrachter.
Und übrigens ist der Typ des Arrays nicht leicht austauschbar, die Variablen Mask und CopyOfFeld müssen nämlich den gleichen Typen haben wie das Feld - das könnte man noch ändern ;-) |
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| type BaseofBitBool = Byte;
BitBoolArray: Array of BaseOfBitBool;
const Size= SizeOf(BaseOfBitBool)*8;
For C:=0 to High(BitBoolArray) do BitBoolArray[C] := round(power(2, Size)-1); |
Und: @Mr_Emre.. soweit sind wir schon dank Gerd Kayser :).. aber ich denke deshalb hast du auch
Mr_Emre_D hat folgendes geschrieben : |
--Doppel |
geschrieben^^
Und: @Horst_H ich arbeite zur Zeit mit Byte und dies klappt kaum langsamer als mit Booleans (0,7) mit deinem 32Bit--32Bool werde ich mich später auseinandersetzten) danke
IhopeonlyReader - Sa 20.04.13 13:21
Guten Tag,
ich habe jetzt 2 verschiedene Bit-Boolean Arten! einmal ein auf einer 32 Bit Grundlage, und einmal auf Byte also 8 Bit Grundlage....
Die 32 Bit Grundlage ist von Horst_H umgesetzt worden :)
und die 8 Byte Grundlage mithilfe von jfheins
Die Units haben ich jeweils im Anhang... das einzige was ich dazu sagen kann:
- im "Alle setzen" ist die 8Bit-Variante schneller !
- im erstellen, loeschen, alle lesen nicht testbar (von mir), da die werte immer schwankten, mal das mal das war größer/brauchte mehr zeit
- im Bereich 1 Bit-Boolean zu schreiben, war die Zeit >1ms und somit zu klein für vergleiche/ Delphi zeigte eine benötige zeit von 0 an.
Deshalb würde ich euch einfach mal bitte diese Units auszutesten und evt. sogar verbesserungen vorzuschlagen :)
Danke für eure Hilfe, IHopeonlyReader (<- schon lange nicht mehr nur Leeser :D)
Delphi-Laie - Sa 20.04.13 19:44
Mathematiker hat folgendes geschrieben : |
Sicher gibt es zwei aufeinanderfolgende Primzahlen mit einem Abstand > 32767, aber die kleinste von denen ist nicht bekannt und wahrscheinlich sehr groß. |
Zumindest gibt es erste Kandidaten für eine solche Lücke: 32769! (hier ist Fakultät gemeint) und ff. .
Dieser Zahl, die keine Primzahl ist, folgen die Garantiert-Nicht-Primzahlen 32769!+2, 32769!+3, ... , 32769!+32769, das sind genau 32768 aufeinanderfolgende Zahlen, die keine Primzahlen sind. Die Differenz zwischen 32769!+1 zu 32769!+32769 müßte 32768>32767 sein, womit wenigstens diese Bedinung erfüllt ist.
Als nächstes wäre "nur" zu klären, ob 32769!+1 eine Primzahl ist.
32770 ist keine Primzahl, mithin auch 32769!+32770 keine (z.B. ist 2 gemeinsamer Teiler beider Summanden).
32771 ist eine Primzahl. Wäre als nächstes "nur" noch zu klären, ob 32769!+32771 eine Primzahl ist (falls ja, dann wäre die Differenz ohnehin schon größer als das oben angegebene Minimum).
Ich hoffe, daß ich mich jetzt nicht allzusehr vertan habe. Das genannte Prinzip, wo große Lücken zwischen den Primzahlen sich befinden
müssen, dürfte aber für die Mathematiker in diesem Forum obertrivial sein.
Mathematiker - Sa 20.04.13 19:58
Hallo Delphi-Laie,
Delphi-Laie hat folgendes geschrieben : |
Zumindest gibt es erste Kandidaten für eine solche Lücke: 32769! (hier ist Fakultät gemeint) und ff. |
Vollkommen richtig.
Delphi-Laie hat folgendes geschrieben : |
Als nächstes wäre "nur" zu klären, ob 32769!+1 eine Primzahl ist. |
Ist es nicht. Die einzigen Faktorprimzahlen n!+1 bis n = 60000 existieren für
n = 1, 2, 3, 11, 27, 37, 41, 73, 77, 116, 154, 320, 340, 399, 427, 872, 1477, 6380, 26951, ..., 110059, 150209.
Von den letzten beiden weiß man nur, dass sie "wahrscheinlich" Primzahlen sind.
Beste Grüße
Mathematiker
Delphi-Laie - Sa 20.04.13 20:02
Ich meinte natürlich "einen ersten Kandidaten für eine solche Lücke". Wie schön & danke, daß Du es gleich aufklären konntest.
IhopeonlyReader - Sa 20.04.13 20:53
Mathematiker hat folgendes geschrieben : |
n = 1, 2, 3, 11, 27, 37, 41, 73, 77, 116, 154, 320, 340, 399, 427, 872, 1477, 6380, 26951, ..., 110059, 150209.
Von den letzten beiden weiß man nur, dass sie "wahrscheinlich" Primzahlen sind.
|
110059 ist die 10458. Primzahl !
150209 ist die 13867. Primzahl
wann die lücke so groß ist werde ich euch bald sagen ;) (dann werde ich alle Primzahlen bis 16.000.000.000.000.000.000 (4Milliarden)² durchgehen und euch sagen können und bis zu dieser riesig großen zahl eine große lücke entsteht, bzw. wie groß die lücke ist).. ich denke das das relativ bald sein wird :D (evt morgen)
Mathematiker - Sa 20.04.13 21:52
Hallo,
IhopeonlyReader hat folgendes geschrieben : |
110059 ist die 10458. Primzahl !
150209 ist die 13867. Primzahl |
Du hast etwas falsch verstanden. Nicht 110059 und 150209 sondern 110059!+1 und 150209!+1 sind gemeint, die erste mit mehr 500000 Ziffern, die zweite mit mehr als 710000.
Ich hatte geschrieben:
Zitat: |
Die einzigen Faktorprimzahlen n!+1 bis n = 60000 existieren für
n = 1, 2, 3, 11, 27, 37, 41, 73, 77, 116, 154, 320, 340, 399, 427, 872, 1477, 6380, 26951, ..., 110059, 150209. |
Wenn Du aber die nachfolgende Tabelle mit Deiner neuen Unit erweitern könntest, wäre das schon sehr gut. Die Tabelle enthält die gegenwärtig bekannten aufeinanderfolgenden, monoton wachsenden maximalen Abstände von benachbarten Primzahlen.
Beste Grüße
Mathematiker
Anhang: Tabelle der größten wachsenden Abstände benachbarter Primzahlen
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: 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:
| Abstand ab bis 1 2 3 2 3 5 4 7 11 6 23 29 8 89 97 14 113 127 18 523 541 20 887 907 22 1129 1151 34 1327 1361 36 9551 9587 44 15683 15727 52 19609 19661 72 31397 31469 86 155921 156007 96 360653 360749 112 370261 370373 114 492113 492227 118 1349533 1349651 132 1357201 1357333 148 2010733 2010881 154 4652353 4652507 180 17051707 17051887 210 20831323 20831533 220 47326693 47326913 222 122164747 122164969 234 189695659 189695893 248 191912783 191913031 250 387096133 387096383 282 436273009 436273291 288 1294268491 1294268779 292 1453168141 1453168433 320 2300942549 2300942869 336 3842610773 3842611109 354 4302407359 4302407713 382 10726904659 10726905041 384 20678048297 20678048681 394 22367084959 22367085353 456 25056082087 25056082543 464 42652618343 42652618807 468 127976334671 127976335139 474 182226896239 182226896713 485 241160024143 241160024628 490 297501075799 297501076289 500 303371455241 303371455741 514 304599508537 304599509051 516 416608695821 416608696337 532 461690510011 461690510543 534 614487453423 614487453957 540 738832927927 738832928467 582 1346294310749 1346294311331 588 1408695493609 1408695494197 602 1968188556461 1968188557063 652 2614941710599 2614941711251 674 7177162611713 7177162612387 716 13828048559701 13828048560417 766 19581334192423 19581334193189 778 42842283925351 42842283926129 804 90874329411493 90874329412297 806 171231342420521 171231342421327 906 219209405436543 219209405437449 916 1189459969825483 1189459969826399 924 1686994940955803 1132 1693182318746371 1184 43841547845541059 1198 55350776431903243 1220 80873624627234849 1370 418032645936712127 1442 804212830686677669 1476 1425172824437699411 |
IhopeonlyReader - Sa 20.04.13 23:02
Da fehlt aber was, wenn ich das richtig verstehe !
deine 7 ist der Abstand von 14.. was mit dem Abstand von 10?
das erste aufeinanderfolgende primzahlen-paar mit dem abstand 10 sind
139 und 149.. ein anderes Beispiel: 337 und 347
Habe ich das jetzt falsch verstanden oder ist die Tabelle wirklich nicht vollständig?
weil zum Abstand von 12, 16, 24, 26, 28, 30, 32 etc. fehlen die paare ja immer..
Mathematiker - Sa 20.04.13 23:19
Hallo,
es geht um das Wachstum der maximalen Primzahlabstände.
Nach dem Abstand 8 zwischen 89 und 97 ist der nächste größere Abstand schon die 14 zwischen 113 und 127.
Abstand 10 folgt erstmals bei 139-149, Abstand 12 bei 199-211. Der größere Abstand 14 war aber eben schon früher aufgetreten.
Eine Tabelle, die für alle möglichen Abstände das kleinste Paar angibt, könnte man auch erstellen. Vielleicht mache ich das einmal.
Beste Grüße
Mathematiker
Nachtrag: Mit dem kleinen Programm
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: 30: 31: 32: 33: 34: 35:
| procedure TForm1.Button1Click(Sender: TObject); var abstand:array[1..1000] of cardinal; a,i,j,grenze:cardinal; z:integer; begin fillchar(abstand,sizeof(abstand),0); listbox1.clear; i:=3; j:=5; a:=1; grenze:=strtoint(edit1.text); repeat while not istprime(j) do j:=j+2; z:=j-i; if (z<1001) and (abstand[z]=0) then begin abstand[z]:=i; listbox1.items.add(format('%4d'#9'%d'#9'%d',[z,i,j])); end; i:=j; j:=j+2; inc(a); if a mod 100000 = 0 then begin label2.caption:=inttostr(j); application.processmessages; end; until j>grenze; z:=2; repeat if abstand[z]=0 then listbox1.items.add(format('%4d'#9'-',[z])); z:=z+2; until z>1000; listbox1.items.savetofile('liste2.000'); end; |
habe ich schnell mal die Liste mit den kleinsten Paaren erstellt, die einen geradzahligen Abstand haben.
istprime ist die Routine, die ich beim Moser-Problem nutze.
http://www.entwickler-ecke.de/topic_Primzahlsummen+MoserProblem_111412.html
Gesucht habe ich bis 1 Milliarde. Der kleinste nicht gefundene Abstand ist 254, der größte gefundene 282.
IhopeonlyReader - Sa 20.04.13 23:48
ok, also sozusagen ein weiteres dyn. Array anlegen und die Primzahlen "normal errechnen" und danach die liste der Primzahlen durchgehen und den Abstand zwischen Primzahl[X-1] und Primzahl[X] errechnen und wenn Abstand > AltAbstand dann zum dyn. Array hinzufügen, das heißt man könnte bis zur "Maximal-Errechenbar-Primzahl" auch den größten Abstand errechnen..
P.S: ich habe gerade germerkt, dass mein Programm THEÒRETISCH bis (4Mrd)² die Primzahlen errechnen könnte!, allerdings wären das 1.862.645.149 GB (1,9 Milliarde GB)
da ich natürlich nicht soviel Ram habe, ist das natürlich nicht möglich :/
Mein Maximum liegt bei ca 12.884.901.890 Millarden.. somit kann ich maximal alle Primzahlen bis 12,8 Milliarden errechnen.. mit der Optimierung dass ich nur "ungerade" zahlen verwende (+1 wegn der 2) dann käm ich bis ca 25 Milliarden..
Und: Mathematiker: "die einen geradzahligen Abstand haben".. ein ungerade Abstand ist (außer bei dem Abstand 1 (von 2 zu 3)) NIE möglich ! denn x,y <- Primzahlen (also ungerade, sonst vielfaches von 2) und x-y-> ungeradezahl-ungeradezahl -> geradezahl (also ist der abstand immer GERADE)
Edit1: Der Abstand von 254 ist gefunden :P
bei dem Primzahlenpaar: 1202442343 und 1202442089
Mathematiker - Sa 20.04.13 23:57
Hallo,
IhopeonlyReader hat folgendes geschrieben : |
Mein Maximum liegt bei ca 12.884.901.890 Millarden.. somit kann ich maximal alle Primzahlen bis 12,8 Milliarden errechnen.. mit der Optimierung dass ich nur "ungerade" zahlen verwende (+1 wegn der 2) dann käm ich bis ca 25 Milliarden.. |
Ich bin schon gespannt.
IhopeonlyReader hat folgendes geschrieben : |
Mathematiker: "die einen geradzahligen Abstand haben".. ein ungerade Abstand ist (außer bei dem Abstand 1 (von 2 zu 3)) NIE möglich ! denn x,y <- Primzahlen (also ungerade, sonst vielfaches von 2) und x-y-> ungeradezahl-ungeradezahl -> geradezahl (also ist der abstand immer GERADE) |
Natürlich ist das so. Die Liste enthält aber nicht den Abstand 1. Und um was wollen wir wetten, dass garantiert einer im Forum mich freundlich daraufhinweisen würde, dass dieser Abstand fehlt. :wink: Und deshalb der Kommentar "geradzahliger Abstand".
Aber es ist nett von Dir, dass Du es für mich beweist. :roll:
Ich habe nochmals bis 2 Milliarden gesucht (Rev 1 der Liste2). Der kleinste nicht gefundene Abstand ist nun 264, der größte gefundene 292.
Beste Grüße
Mathematiker
IhopeonlyReader - So 21.04.13 00:03
Mathematiker: Der kleinste nicht gefundene Abstand ist nun 264:
Nicht mehr:
2357881993 und 2357882257
Edit: das fehlende paar zu dem fehlenden Abstand von 286 lautet:
2842739311 und 2842739597 (und ein weiteres liegt bei ca 4,05 mrd)
Mathematiker - So 21.04.13 08:36
Hallo,
ich habe mein altes Primzahlsieb wieder ausgekramt und für die Suche nach Primzahlabständen modifiziert. Grundlage ist
Gammatester mp_arith.
Blockweise werden jeweils 5 Millionen Zahlen gesiebt und danach ausgewertet. Abstände ermittle ich nur ab 200 und die Startzahl sollte auch nicht kleiner als 100 Millionen sein.
Natürlich ist dies nicht so schnell wie Dein Sieb, hat aber den Vorteil, dass es nach "oben offen" ist.
Wenn Dein Computer schnell genug ist und Du ihn quälen willst, kannst Du auch bis in die Billionen hinein suchen.
Mein PC ist im Moment bei 14 Milliarden und bis 332 sind alle Abstände gefunden.
Beste Grüße
Mathematiker
Nachtrag: Ab 30827138509 folgt ein Abstand mit 334. Jetzt bis 35 Milliarden gesucht und kein Paar für 362.
Nachtrag 2: Ich habe eine Erweiterung (Rev 1) eingebaut. Markiert man Weiterrechnen, so werden bei Abbruch die erzielten Ergebnisse in liste.txt gespeichert und beim Neustart an dieser Stelle weitergerechnet.
Jetzt bin ich bei 52 Milliarden. Der kleinste fehlende Wert ist 370, bis 1000 fehlen insgesamt noch 297 Paare.
Rev 2:
Horst_H hat einen bösen Fehler in meinem Programm gefunden. Ich hoffe, dass er jetzt behoben ist. Danke für den Hinweis.
IhopeonlyReader - So 21.04.13 15:38
Freut mich :)
Und ich denke in meinem prog brauch ich das nicht einbauen.. denn
1. mein prog geht nur bis 12 Milliarden und
2. ich bin mir nichtmal mehr sicher, dass meins schneller ist^^
denn vorher habe ich die primzalhne bis 4 Milliarden in ca 15 sek ausgerechnet.. inzwischen bin ich bei nur noch 50 sek (Bit-Boolean)..
ich wüsste zwar jetzt weitere "verkleinerungsmaßnahmen" wie Array halbieren, da nur ungerade zahlen Primzahlen sein können, oder Nach 4 Mrd BooleanArray gegen Int Array ersetzen und nur "richtige" abspeicher.. sozusagen wird aus
Bool[1] (false)
Bool[2] (true)
Bool[3] (true)
Bool[4] (false)
Bool[5] (true)
dann
Int[1] := 2;
Int[2] := 3;
Int[4] := 5;
webei ich natürlich dann wie schon erwähnt wurde nur die Differenz abspeichern müsste, hierdurch wäre kein 32Bit Variable nötig, sondern eine 16bit variante würde reichen (z.B. Word)
aber das würde alles die rechenzeit so stark erhöhen, dass ich mich jetzt daran mache ein nach oben offenes sieb zu programmieren
Denn: ich denke DIREKT auf Minimialer Ram zu programmieren ist letztendlich schneller, als auf Zeit zu programmieren und dann auf Ram zu optimieren
Horst_H - So 21.04.13 16:13
Hallo,
@
Mathematiker:
Wie kannst Du bis 52x1e9 nur noch 297 fehlende haben:
http://primes.utm.edu/notes/GapsTable.html
Zitat: |
gap Auftreten bei
463 42.652.618.343
467 127.976.334.671 |
Mist, Du bist bei 52x10e9 Primzahl also bei
Zitat: |
803 90.874.329.411.493 [Nicely99] |
Tatsächlich hat mein Programm 2h17 min für die Primzahlen bis 1e12 gebraucht.
Zitat: |
539 738832927927 .. 738832928467 |
Aber ich habe noch das Auftreten der Abstände gezählt, die im unterern Bereich nicht stimmt, weil ich vorgesiebtes Sieb nutze, in dem 2,3,5,7,11,13 und deren Vielfache fehlen.
Exemplarisch
Zitat: |
479 4
477 2
475 2
473 10
471 3
469 4
467 5
465 2
463 3
461 12
...
19 1298682892
17 2246576317
15 1202533146
13 1556469349
11 2753597777
9 2052293026 |
12 und 18 kommen als Abstand am häufigsten vor.
Gruß Horst
Edit 16:40 Uhr:
In so hohen Zahlbereichen ist so simples sieben zu langsam.50,8 Mio zahlen zu verarbeiten, wovon über 99 % ( ab 10 Mio) bei jedem Durchgang nicht im Sieb landen ist sehr uneffektiv.
deshalb hatte Gammatester mal vorgeschlagen einfach mit den ersten Primzahlen bis 2^16 zu sieben und dann erst Miller-Rabin zu starten.Wenn die 6542 Zahlen gesiebt haben, wobei Zahl und Uebertrag vom Typ word sein können und dann der Test kommt, muss ich hier noch 50.8 Mio Zahlen ( Zahl Dword, Uebertrag int64 )verarbeiten.In der Zeit kann man viele Miller-Rabin Tests machen.
Mathematiker - So 21.04.13 16:58
Hallo Horst_H,
Horst_H hat folgendes geschrieben : |
Tatsächlich hat mein Programm 2h17 min für die Primzahlen bis 1e12 gebraucht. |
Gratulation. Das ist richtig schnell. Für 1 Billion brauche ich geschätzt 16 Stunden.
Horst_H hat folgendes geschrieben : |
In so hohen Zahlbereichen ist so simples sieben zu langsam.50,8 Mio zahlen zu verarbeiten, wovon über 99 % ( ab 10 Mio) bei jedem Durchgang nicht im Sieb landen ist sehr uneffektiv. |
Deshalb siebe ich mit 41537 Primzahlen (ohne 2) bis 499979 und überlasse den Rest dem Rabin-Miller-Test.
Nachdem ich gesehen habe, dass das Thema im Netz schon soweit abgearbeitet ist, dass schon Paare mit 2000 und mehr Abstand gefunden wurden (wohin ich mit meinem Programm nie komme), habe ich die Suche auf "einsame Primzahlen" abgeändert.
Unter einer einsamen Primzahl versteht man eine Primzahl p, deren Summe s der Abstände zur vorhergehenden und zur nachfolgenden Primzahl größer ist, als bei jeder vorhergehenden Primzahl.
Zum Beispiel ist die 211 eine einsame Primzahl. Die vorhergehende Primzahl ist 199, die nachfolgende 223. Deren Abstand ist mit 24 so groß, wie bei keiner Primzahl < 211.
Dazu habe ich im Netz noch nicht viel gefunden. Man kann also "Geschichte schreiben". :wink:
Gegenwärtig ist mein Programm bei 13 Milliarden (15 Minuten) und hat als größte einsame Primzahl 10726905041; Abstand 438 von 10726904659 bis 10726905097 gefunden.
Beste Grüße
Mathematiker
IhopeonlyReader - So 21.04.13 17:23
Wunderbar :) soviele Primzahl Verwendungszwecke^^
Mathematiker: du beschäfitgst dich also mit "einsamen Primzahlen"
Horst_H: du beschäftigst dich also mit dem Abstand?
Dann werde ich mal zurückspringen und eine Liste der "immer größer werdenden Abstände zwischen den Primzahlen" erstellen (bis 4 Mrd)
Und: @alle^^ warum kann Delphi nicht über 2^32 -1 hinaus ? (ja Delphi ist eine 32-Bit Anwendung und somit ist 2^32 -1 die größte mögliche zahl...)
aber Cardinal*Cardinal = >2^32 -1 ... IMMER ! hierdruch erreiche ich viele Fehler :(
also Beispiel:
4 Mrd * 2 = 8Mrd (wäre logisch) mein Delphi spuckt aber ganz komische zahlen aus... (z.B. 3.705.032.704 also ca 3,7 Mrd)
Ihr könnt es ja auch mal testen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| var C,X: Cardinal; begin X := 4000000000; C := 2; Showmessage( IntToStr( C*X ) ); end; |
hierdurch kann nich nämlich keine Primzahlen > 2^32 -1 errechnen :(
teilweise wird auch:
Zitat: |
Überlauf bei Konvertierung oder arithmetischer Operation
|
ausgegeben...
mandras - So 21.04.13 17:30
Cardinal ist vorzeichenloser Int, insofern halt bis 2^32-1.
Dein Ergebnis sind die Bits 0-31 des korrekten Produktes.
Für Größere Zahlen: int64 nehmen
IhopeonlyReader - So 21.04.13 20:08
IhopeonlyReader hat folgendes geschrieben : |
1 im "Alle setzen" ist die 8Bit-Variante schneller !
2 im erstellen, loeschen, alle lesen nicht testbar (von mir), da die werte immer schwankten, mal das mal das war größer/brauchte mehr zeit
Deshalb würde ich euch einfach mal bitte diese Units auszutesten und evt. sogar verbesserungen vorzuschlagen :)
|
Da sich dazu noch keiner wirklich geäußert hat... habe ich mein Sieb des Eratosthenes mal auf beide Varianten aufgebaut.. (dank der Units nur 3 kleine Änderungen (uses list ändern, typ von TBitBooleans8 zu TBitBooleans32 ändern, beim erstellen anstatt TBitBooleans8.erstellen(Anzahl) TBitBooleans32.erstellen(Anzahl)) also die 8 durch 32 ersetzten
Bei vielfachen Lesen und schreiben, sind hier ein paar Verwerte zum Vergleich:
Zitat: |
Basis (8 oder 32)...............Primzahlen bis:...............Initialiserung (alle Setzen)...............Zeit (für alle Berechnungen und Zugriffe auf Booleans)
8..............................100mio..............................0,03..................................................2,668
32..............................100mio..............................0,58..................................................2,21
8..............................1 Mrd...............................0,28..................................................28,174
32..............................1 Mrd...............................5,43..................................................24,54
8..............................2 Mrd................................0,53.................................................57,877
32..............................2 Mrd................................11,51................................................50,099
8..............................3 Mrd................................0,76.................................................92,261
32..............................3 Mrd................................16,5.................................................77,66
8..............................4 Mrd................................1,03 ................................................120,104
32..............................4 Mrd................................21,6 ................................................104,5
|
Fazit: Zum einzelnen Lesen/Schreiben ist die Bit-Boolean Variante aufbauend auf 32 Bit schneller ( ca 13% schneller )
Allerdings braucht man zum initialisieren ca 20x so lang! Somit ist die GesamtZeit größer als die zum 8 Bit Variante...
Wenn es eine Möglichkeit gäbe, die 32-Booleans aufeinmal auf True/False zu setzen wäre die 32 Bit variante geeigneter, so allerdings ist bei kleinen Berechnungen die 8 Bit Variante besser :)
(Für alle die sich fragen warum das so ist: 1. Schaut euch die Units doch einfach an^^... das liegt daran, dass bei der 8Bit Variante Byte als Grundlage genommen wird, wenn man also alle Bits auf True setzen will, setzt man den ganzen Byte auf 255 (2^8 -1), will man alle Bits in dem Byte auf 0 setzten so genügt es das Byte auf 0 zu setzen.. Bei der 32er Variante wird jedes einzelne Bit durchgeganen)
um 64 Bit-Booleans auf True zu setzen, wird bei der 32-variante 2x32 Bits auf 1 gesetzt, bei der 8-variante 8x1Byte auf 255 gesetzt
somit stehen 64 den 8 gegenüber... ebenfalls dauert es länger ein Bit auf True zu setzen, als ein Byte einem Wert zuzuweisen (komisch?!)
hierdurch entsteht das 20 zu 1 verhältnis
IhopeonlyReader - So 21.04.13 20:18
wieso wird gesagt
if ( (VMrd)>=floor(power(T, 1/2))) then
ergäbe immer True? wenn T>(4Mrd)² ist dann nicht! oder sieht Delphi dann nur den Bereich bis 2^64 -1 (aber selbst dann.. die wurzel davon wäre nämlich ca 2^32 und somit >4Mrd?
jfheins - So 21.04.13 20:48
Aber beim 32bit kann man das doch genau so machen??
Delphi-Quelltext
1: 2: 3:
| var x: Cardinal; begin x := $FFFFFFFF; end; |
oder so...
IhopeonlyReader - So 21.04.13 20:51
@jfheins
schau dir bitte erstmal die Zusammentsetztung der 32-Bit-Variante von Horst_H an...
Zitat: |
Verfasst: Mi 17.04.13 13:01 |
oder lade dir die Unit (32Variante) von mir herunter (beides in diesem Topic auf seite 2)
Denn die 32er Variante basiert NICHT auf Integer, Cardinal oder so..
Gerd Kayser - So 21.04.13 21:21
IhopeonlyReader hat folgendes geschrieben : |
Fazit: Zum einzelnen Lesen/Schreiben ist die Bit-Boolean Variante aufbauend auf 32 Bit schneller ( ca 13% schneller )
Allerdings braucht man zum initialisieren ca 20x so lang! |
Beim Sieb des Erastothenes kann man doch die Zahlen entsprechend vorinitialisieren. Nehmen wir mal an, ein nicht gesetztes Bit bedeutet keine Primzahl. Bei einem Integer ist das höchstwertigste Bit links, das niederwertigste Bit rechts. Statt nun beim Initialisieren alle Bits auf 1 zu setzen, kann man auch gleich alle geraden Zahlen auf 0 setzen. Das erspart das Sieben mit der Primzahl 2. --> 01010101010101010101010101010101. Das entspricht dezimal 1.431.655.765. Danach müssen einmalig zwei Bits im ersten Integer anders gesetzt werden (1 keine Primzahl, 2 gleich Primzahl).
Man kann natürlich auch die ersten Primzahlen beim Initialisieren berücksichtigen: 2, 3, 5, 7. Dazu braucht man ein kleines Array of Integer. Die Anzahl der benötigten Integerwerte berechnet man mit dem kgV: 3^1 * 5^1 * 7^1 * 2^5 = 3360 Bits = 105 Integer. Beim 106. Integer würde es wieder von vorne beginnen. Mit diesen 105 Integern kann man fortlaufend das große Array initialisieren. Danach auch hier das erste Integer anpassen. Danach kann man beim Sieben mit der Primzahl 11 anfangen. Das sollte die Sache schon etwas beschleunigen.
Edit: Rechenfehler beim kgV korrigiert.
IhopeonlyReader - So 21.04.13 21:38
das ist ne gute Idee ;) so erspare ich mir 25% rechenzeit^^
das ist mit beiden möglich, allerdings ist dann die 8 BitVariante immer noch 20x schneller! (wenn nicht noch schneller), da man bei der 32bit variante dann bit für bit immer abwechseln auf 1 und 0 setzen..
bei der 8erVariante setzte ich einfach das 1 Byte auf 172 (10101100)
die anderen auf 170 (10101010)
die abfrage beginne ich dann erst mit 3
Edit: 18% schneller
jfheins - So 21.04.13 21:59
Ach ja, wenn ihr natürlich mit Sets arbeitet, dann schaut das ungefähr so aus:
Delphi-Quelltext
1: 2: 3: 4:
| var x: tBoolSet; begin Cardinal(x) := $FFFFFFFF; end; |
Das geht aber echt nur mit der 32bit Version. (Mit einem cast auf UInt64 vielleicht auch noch bei 64 bit)
Man könnte aber auch die Byte-variante auf Cardional erweitern. Müsste dann ebenso schnell laufen, letztlich ist das set of ... ja nur syntactic sugar für die Bitmasken und entsprechende bitweisen Operationen.
IhopeonlyReader - So 21.04.13 22:27
warum mit dem Hexadezimalsystem arbeiten (F)
man könnte genausogut (und leichter verständlich) 4294967295 verwenden.. vorallem ist es dann leichter einzelne bits bei der initialiserung direkt zu ändern´(da man dann einfach "errechnen" kann welche zahl 1010101010101010.. ist, als das ganze im hexadeximalsystem zu schreiben.. (ein F setzt ja direkt 4 Bits)
Edit: aber das mit Cardinal(x) := ... wusste ich nicht :) danke ;)
Gerd Kayser - So 21.04.13 22:33
Man kann das noch weiter beschleunigen:
Nehmen wir mal die 3 als Primzahl. Man braucht dann nicht von der Zahl 3 ausgehend jede dritte Zahl zu prüfen, also 3, 6, 9, 12, 15 usw. Wie man sehen kann, erfolgt jede zweite Prüfung bei einer geraden Zahl, die ja keine Primzahl sein kann. Als Schrittweite beim Prüfen bietet sich also die doppelte Primzahl an: 3, 9, 15, 21 usw. (Schrittweite jeweils 2 * 3). Das gilt auch für alle anderen Primzahlen (außer bei der 2).
jfheins - So 21.04.13 23:07
IhopeonlyReader hat folgendes geschrieben : |
warum mit dem Hexadezimalsystem arbeiten (F)
man könnte genausogut (und leichter verständlich) 4294967295 verwenden.. vorallem ist es dann leichter einzelne bits bei der initialiserung direkt zu ändern´(da man dann einfach "errechnen" kann welche zahl 1010101010101010.. ist, als das ganze im hexadeximalsystem zu schreiben.. (ein F setzt ja direkt 4 Bits) |
Ja,
gerade deshalb bietet sich das Hexadezimalsystem ja an :wink:
Wenn du jetzt 10101010 in hex haben möchtet, kann ich das im Kopf: $AA. Wenn du jetzt 1010101010101010 willst, ganz einfach: $AAAA.
Ganz anders bei der Umrechnung ins Dezimalsystem: 170 und 43.690 sehen sich auf den ersten Blick nicht ähnlich. (43.690 = 170 * 257)
Und wenn du 4294967295 schreibt, habe ich keine Ahnung, ob das jetzt 2^32 ist oder 2^32+1 oder 2^32-1 oder whatever. Ich weiß dass es
ungefähr 2^32 ist - mehr aber auch nicht. Bei $FFFFFFFF weiß ist sofort was Sache ist. (=2^32-1) Du siehst, bei Dezimaldarstellung muss man immer nachrechnen, bei Hexadezimaldarstellung kann man es direkt sehen.
Vor allem unverständlich ist das hier:
Zitat: |
[Mit dezimal ist es]leichter einzelne bits direkt zu ändern |
Weil im Hex-System ist eine Ziffer genau 4 bits. Wenn du also ein Bit ändern möchtest, weißt du sofort welche Ziffer du wie abändern musst. Bei Dezimal ist eine Ziffer 3,32 bits. Und da in der basis die 5 mit drin steckt, ändern sich mal gleich alle Ziffern, die niedriger sind als dein Flag. Das soll
einfach sein?
IhopeonlyReader - Mo 22.04.13 17:07
naja.. ich mache das so (am Beispiel Byte (8Bit) da es da nur 8 und nicht 32 bits sind )
1 Ich screibe auf, wie es aussehen muss (von den Bits) :
1 0 1 0 1 0 1 0
2. ich schreibe auf, welche werte das sind (von hinten angefangen)
1 2 4 8 16 32 64 128 (dann eben schnell umdrehen)
128 64 32 16 8 4 2 1
(und dann da wo 1en sind addieren)
128+32+8+2
= 170
so kann ich sozusagen direkt Cardinal(x) := 170;
bei deiner Methode check ich noch nicht wie ich das SCHNELL machen soll^^
1 0 0 0 = 2^3 = 8
also bei deiner Hexadezimalschreibweise 8
bei
1 1 1 1 = 2^4 -1 = 16-1= 15
bei deiner Schreibweise F
1 0 1 0 = 2^3+2^1 = 8+2 = 10
bei deiner Schreibweise A
wenn ich also zu deiner Hexadezimalschreibweise kommen will, unterteile ich die Bits in 4er-Teile und rechne den Wert aus, dafür setze ich dann den Buchstaben/Ziffer.. verstehst du jetzt warum das für mich komplizierter ist? oder gibt's ne einfachere Variante?
IhopeonlyReader - Mo 22.04.13 17:23
Gerd Kayser hat folgendes geschrieben : |
Nehmen wir mal die 3 als Primzahl. Man braucht dann nicht von der Zahl 3 ausgehend jede dritte Zahl zu prüfen, also 3, 6, 9, 12, 15 usw. Wie man sehen kann, erfolgt jede zweite Prüfung bei einer geraden Zahl, die ja keine Primzahl sein kann. Als Schrittweite beim Prüfen bietet sich also die doppelte Primzahl an: 3, 9, 15, 21 usw. (Schrittweite jeweils 2 * 3). Das gilt auch für alle anderen Primzahlen (außer bei der 2). |
Theoretisch: Muss man 1. muss man bei den Quadratzahlen beginnen...
also wenn ich alle vielfache von 5 z.B: rausstreichen will, muss ich bei 5x5 (25) anfangen, da 5x2 = vielfaches von 2 5x3 = vielfaches von 3 und 5x4 = 5x2x2 = vielfaches von 2..
somit muss man 5 nicht immer von 2 erhöhen (mache ich bereits), sondern kann 5 am anfang x5 nehmen dann Primzahl1nach5 (7) wäre dann 5x7=35,
danach Primzahl2nach5 (11) = 5*11 = 55.. etc, (es muss nur Primzahl*Primzahl gerechnet werden, da alles andere vielfache von anderen zahlen sind und somit schon draußen sind (40 von der 2, 45 von der 3)
da aber die "größeren" Primzahlen fehlen muss man dort "jeden 2ten" nehmen, da (x)*y*Primzahl da wenn x=gerade dann ist das Ergebnis ein vielfaches von 2...
aber wie gesagt, dass ist alles drin ;) ich rechne auch nur bis "abgerundete wurzel von BisXsuchen"
IhopeonlyReader - Mo 22.04.13 17:57
- die 32-BitBooleans Unit wurde aktualisiert (Rev 1) -
IhopeonlyReader - Mo 22.04.13 22:07
IhopeonlyReader hat folgendes geschrieben : |
Mein Maximum liegt bei ca 12.884.901.890 Millarden.. somit kann ich maximal alle Primzahlen bis 12,8 Milliarden errechnen.. mit der Optimierung dass ich nur "ungerade" zahlen verwende (+1 wegn der 2) dann käm ich bis ca 25 Milliarden.. |
ohne Optimierung kann ich (wie vorrausgesagt) bis ca 12,5 Mrd. die Primzahlen berechnen !
Es gibt bis 12 Mrd 541.555.851 Primzahlen
kann das mal wer nachprüfen ob das stimmt?
Edit: die abgespeicherte Datei mit allen 541 Mio Primzahlen ist ca 6,08 GB groß.. OpenOffice, Word, Editor.. alle versagen :( kennt wer ein prog. das solch RIESEN Dateien "einigermaßen schnell" öffnen kann?
Mathematiker - Mo 22.04.13 23:02
Hallo,
IhopeonlyReader hat folgendes geschrieben : |
Es gibt bis 12 Mrd 541.555.851 Primzahlen
kann das mal wer nachprüfen ob das stimmt? |
Genau wird heute abend nicht mehr. Aber für den Integrallogarithmus ergibt sich
Li(12000000000) = 541562074
d.h. etwa der Wert. Mit der zuerwartenden Abweichung wird es also wohl stimmen.
Beste Grüße
Mathematiker
Nachtrag: Ich habe 541555852 beim exakten Sieben gezählt. Ist bei Dir die 2 dabei?
IhopeonlyReader - Di 23.04.13 13:22
Mathematiker hat folgendes geschrieben: |
Nachtrag: Ich habe 541555852 beim exakten Sieben gezählt. Ist bei Dir die 2 dabei? |
ja ALLE Primzahlen bis 12 Milliarden...
danke für die Seiten
Gammatester :), ich rechne gerade Primzahlen bis 13,5 Milliarden aus, da die Grenze bei Delphi scheinbar zwischen 1,5 und 1,6 GB liegt... weiß der Geier warum ... kann mir bitte jemand mal die Antwort vom Geier nennen?
IhopeonlyReader - Di 23.04.13 14:43
.. ich habe bei mir einen Fehler in der Berechnung bemerkt !
Als der Fehler (noch) drin war, habe ich folgende Ergebnisse gehabt:
Bis 12 Mrd gibt es 541.555.851 Primzahlen
Bis 13,5 Mrd gibt es 606.022.680 Primzahlen
nach den "Tabellen" sind diese Angaben richtig !
Ich werde das ganze nochmal "ohne" den Fehler berechnen und schauen ob ich Glück gehabt habe, das bei solch kleinen Zahlbereichen (bis 15 Mrd) der Fehler noch nicht in Kraft getreten ist, aber eigentlich müsste sich der Fehler ab ca 4Mrd +8 zeigen..
Horst_H - Di 23.04.13 14:54
Hallo,
da wollte
Gammatester mich wohl foppen ;-)
Ich habe mal seine Version etwas modifiziert, ohne das ganze "Gedöhns" seiner umfangreichen Ganzzahlarithmetik drumherum.Dadurch natürlich wesentlich langsamer, denn ich wollte diesen rückwärts Index nicht ala PrimIndex16(4)= 2.
Wollte ich das für die Primzahlen bis 1e9 machen, hätte ich keinen Speicher dafür.
Also schätze ich den Index ab Pi(x)= Index ~ sqrt(x)/(ln(sqrt(x))-1.08366) und suche dann in den Primzahlen, entsprechen rauf oder runter.
Als anderes wäre mir noch eingefallen, eine Tabelle für 65536 Zahlen ( X shr 16 ) mit dem Index ins Primzahlen Feld und dann linear mit (X MOD 65536) zu interpolieren und dann suchen. ( Tabelle[0]= 1,Tabelle[1] = 6542, )
Etwas lahm:
Quelltext
1:
| Lehmer: WE mit lsumphi32 [s]: 00:00:01.611 PrimePi(12000000000) = 541555851 |
Natürlich hätte ich für kleine X Primes16Index behalten können, das wird am häufigsten gebraucht.
Gruß Horst
EDIT:
Neue Version das bringt doch einiges...
Quelltext
1:
| Lehmer: WE mit lsumphi32 [s]: 00:00:00.779 PrimePi(12000000000) = 541555851 |
Ich habe vergessen zu sagen es Funktioniert nur bis 1e12, wie Primes1E6 vermuten lässt
Aaaaahhhhhh Edit3:
Zu wenig Int64 eingesetzt, denn bei mehr als 2x1e9 Primzahlen gab es wunderliche Ergebnisse.Deshalb jetzt ein Test bis 1e12:
Quelltext
1:
| Lehmer: WE mit lsumphi32 [s]: 00:00:33.719 PrimePi(1000000000000) = 37607912018 |
Das passt.
Gammatester - Di 23.04.13 15:41
Sehr cool 8)
Horst_H hat folgendes geschrieben : |
Ich habe vergessen zu sagen es Funktioniert nur bis 1e12, wie Primes1E6 vermuten lässt |
Es funktioniert auch darüber hinaus, wenn man ein Anpassungen vornimmt (FPC und D9+, Source im Anhang) und ein wenig Zeit hat, hier für den 10fachen Wert = 120 Milliarden
Quelltext
1: 2: 3: 4:
| C:\Download>prime_pi64.exe PrimePi mit MPArith V (c) 2012 Mathematiker/WE(Gammatester) 78500 1000027 Lehmer: WE mit lsumphi32 [s]: 00:00:25.560 PrimePi(120000000000) = 4904759399 |
Gruß Gammatester
Edit: Mist, zu spät.
IhopeonlyReader - Di 23.04.13 15:48
so, für alle die einige Probleme mit deinem Projekt haben..
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| testnum = 12*1000*1000*1000; testnum = 12000000000; Primes1E6 : array[1..NumPrimes1E6+8] of DWord; DWord = LongWord Primes1E6 : array[1..NumPrimes1E6+8] of LongWord; c := Primes1E6Index(trunc(exp(ln(x)/3.0)+0.5)); c := Primes1E6Index(trunc(exp(ln(x/1)/3.0)+0.5)); (ln(x/1); |
Horst_H - Di 23.04.13 15:54
Hallo,
Uups, wieso muss man das ausdrücklich umwandeln? Bei Freepascal 2.6.2 nicht.
Ist ja zum Glück aber auch nur ein kleines Problem, das
Gammatester in seiner Version richtig gemacht hat.
Gruß Horst
P.S.
Alles sehr Offtopic ;-)
Mathematiker - Di 23.04.13 15:56
Hallo Horst_H,
die Bestimmung der Primzahlanzahl ist superschnell. Starke Leistung! Genau das habe ich für int64 schon längere Zeit gesucht. Vielen Dank.
@IhopeonlyReader
Bei meinem Siebversuch bis 12 Milliarden habe ich wohl eine Primzahl "doppelt" gezählt. Entschuldigung.
Beste Grüße
Mathematiker
IhopeonlyReader - Di 23.04.13 16:00
Mathematiker hat folgendes geschrieben : |
@IhopeonlyReader
Bei meinem Siebversuch bis 12 Milliarden habe ich wohl eine Primzahl "doppelt" gezählt. Entschuldigung.
|
Klar, kein Problem ;) Und wie gesagt, ich habe in meinem Sieb ebenfalls ein Fehler drin^^, ich rechne gerade nochmal bis 13,5 Milliarden aus... (scheint aber so, als wenn der fehler sich automatisch ausgeglichen hätte (const+1 = const) <- war so^^.. dadurch hat sich der Fehler scheinbar selbst behoben^^.. aber ich rechne lieber nochmal ohne fehler :D
Nachtrag:
Horst_H hat folgendes geschrieben : |
P.S. Alles sehr Offtopic ;-) |
Ich glaube wir sollten mal einen Mod? bitten ob er ab Seite 2 (meiner Unit Veröffentlichung) das ganze mal trennt in ein neues Topic namens "allg. Primzahlenprobleme"
Nachtrag 2:
Mathematiker hat folgendes geschrieben : |
Bei meinem Siebversuch bis 12 Milliarden |
wie lange hat dein Rechner dafür gebraucht?
Mathematiker - Di 23.04.13 17:50
Achtung!
Beim Aufruf der von Gammatester angegebenen Seite
http://www.primefan.ru/stuff/primes/10(07)11.txt
meldet mein Virenscanner:
"Exploit:HTML/IframeRef.gen" Schwerwiegende Warnstufe!
Also entweder spinnt der Virenscanner oder irgendetwas läuft im Moment schief. Jahrelang gab's so etwas bei mir nicht und jetzt in wenigen Tagen das 2.Mal. :nixweiss:
Sorry, war eine Fehlmeldung. :autsch:
Beste Grüße
Mathematiker
Tranx - Di 23.04.13 18:01
Also, die Endung .ru ist in dem Link schon höchst verdächtig. Eine rumänische Seite!!! Na, wenn das man nicht wieder ein Trojaner-Ding ist. ;)
IhopeonlyReader - Di 23.04.13 18:02
Zum Thema "ich habe ein Fehler eingebaut"
Fehlerbehebung (automatisch):
Ich habe ein 2D Array angelegt, um den Index weiterhin "vernünftig" angeben zu können, somit unterteile ich bei meinem Sieb die zu berechnenden Zahlen in Vmrd -Teile (4 Milliardener Schritte) somit geht das 1 BitBoolean Array (mit dem Index 0) von der Zahl 0 bis hin zur Zahl 4Mrd-1
da ich die Bytes voll ausnutzen wollte unterteilte ich das Array nicht in 4Mrd-Schritte sondern in (4Mrd+7)er Schritte...
instinktiv (oder glück :D) nutzte ich nun um herauszufinden in welchem "Teil" das BitBoolean liegt die Div variante mit VMrd+1 (also zB. 1Mrd div (VMrd+1) =0 also im Teil mit dem index 0)
Dies führt natürlich zu einem Fehler (theoretisch), da das 4 Mrd + 7 bit-boolean ja gar nicht im teil mit dem index 0 existiert, ABER ich habe ja zur Grundlage ein Byte und dieser besteht aus 8 Bits, da 4Mrd+7 nicht durch 8 Teilbar ist, bleibt 1 "ungenutztes" Bit.. dies wurde dadurch RICHTIG beschrieben und genutzt...
Wenn ich als Grundlage eine Zahl, die ein vielfaches von 8 ist, genommen hätte, hätte ich direkt eine exception erzeugt... So hatte ich glück.. ich habe nun alle (VMrd+1) durch ein VMrdD ersetzt (soll soviel heißen wie VMrd Divisor) dieser setzt sich nun folgender Maßen zusammen: VMrdD = VMrd + (VMrd mod 2);
Falls ihr euch fragt "nur weil man ungeschriebene bits nicht genutzt hat, soll dein Ergebnis falsch sein?"
so hier die Antwort: Nein, nicht direkt weil man ungeschriebene bits nicht nutzt, sondern weil die zahl VMdr ungerade ist!, denn ich setzte die Bytes auf 170 also 10101010 (gerade zahlen auf false, ungerade auf true) ist nun aber der Teil ungerade, so wird in jedem Teil, deren Index ungerade ist (1,3 ...) jede gerade zahl auf true und jede ungerade zahl auf False gesetzt..
Behebung: ich könnte jetzt natürlich VMdrD = VMdr + (VMdr mod 8 ) schreiben, um wirklich ALLE "erstellen" bits zu nutzen, da ich ich aber erstmal nur FEHLER vermeiden will, bringe ich es auf eine "gerade" zahl also mod 2 !
jfheins - Di 23.04.13 18:44
Mathematiker hat folgendes geschrieben : |
meldet mein Virenscanner:
"Exploit:HTML/IframeRef.gen" Schwerwiegende Warnstufe! |
Also die URL zeigt bei mir auf eine stinknormele Textdatei. Da ist kein bisschen html Code. Ich würde daher (falls der Fehler immer noch besteht) mal auf deinen PC tippen.
Tranx hat folgendes geschrieben : |
Also, die Endung .ru ist in dem Link schon höchst verdächtig. Eine rumänische Seite!!! Na, wenn das man nicht wieder ein Trojaner-Ding ist. ;) |
Und .ru ist natürlich Russland ;-)
Mathematiker - Di 23.04.13 19:01
Hallo,
jfheins hat folgendes geschrieben : |
Mathematiker hat folgendes geschrieben : |
meldet mein Virenscanner:
"Exploit:HTML/IframeRef.gen" Schwerwiegende Warnstufe! |
Also die URL zeigt bei mir auf eine stinknormele Textdatei. Da ist kein bisschen html Code. |
Nachdem ich per Hand alle(!) temporären Internetdateien gelöscht habe, gibt's bei mir auch keine Meldung mehr. Der Virenscanner hatte wohl doch nicht alles gelöscht.
Damit hat sich meine Warnung als Fehlmeldung erwiesen. Tut mir leid für die "Panikmache". :autsch:
Beste Grüße
Mathematiker
IhopeonlyReader - Di 23.04.13 19:36
So, ich habe mein Programm nun soweit PERFEKTIONIERT, dass es alle Primzahlen bis ((4 Mrd+8)^2) -1 ausrechnen kann.. bis auf eine kleiner Ausnahme^^ Delphi7 erzeugt *32 Anwendungen, diesen wird nun einmal nicht mehr als 2 GB zur Verfügung gestellt, und diese 2GB müssen sich auch noch ALLE Programm teilen...
deshalb habe ich mich mal versucht zu informieren:
http://www.3dcenter.org/artikel/das-large-address-aware-flag
somit komme ich nun "nur" auf 1,6 GB nutztbaren Arbeitsspeicher (ram) also 1,6*1024^3 *8 Booleans und somit "Werte" also bis 13,7 Milliarden, da ist bei mir Schluss.. so ist selbst bei Vollausnutzung (2GB) der Maximalwert bei 17,18 Mrd erreicht... (abgesehen davon, dass solche abgespeicherten Primzahlen.txt s 10 GB groß wären) ist mir das zu wenig...
was ich tun werde:
Optimierung auf:
1. UngeradenArray+2 so steht dann das erste Bit für folgende zahlen
BitNr (0-7) Zahl (wert)
0................1
1................3
2................5
3................7
4................9
5................11
6................13
7................15
Um auszurechnen welche zahl das bit eigentlich wiedergibt würde ich dann (BitNr+1)*2-1 = (BitNr+0.5)* 2 oder 2*BitNr +1
Um auszurechnen in welchem Bit die Zahl steht ensprechend (Zahl-1) div 2 bzw. Zahl div 2 (da DIV ja immer abrundet)
Ersparnis: 50% (Primzahlen bis max. 35 Mrd möglich, unter "normalen" Auslastungen nur bis 27 Mrd)
2. Nach der Berechnung bis VMrd (ein Teil), so "kürze" ich diesen..
Beispiel: aus dem 10 BitBooleans enthaltenenden Array von 0 bis 9
ArrayIndex steht für Zahl Wert
0................1................False //eigentlich True, wird aber am anfang direkt auf false gesetzt, da es ja keine Primzahl ist
1................3................True
2................5................True
3................7................True
4................9................False
5................11................True
6................13................True
7................15................False
8................17................True
9................19................True
wird ein neues Array, allerdings nicht aus booleans sondern aus Int64 (hier würde Byte reichen, aber es geht ja bis 16x10^18 hoch) zahlen
ArrayIndex Inhalt
0................3
1................5
2................7
3................11
4................13
5................17
6................19
das wird weiter auf den Abstand zur vorherigen primzahl gekürzt, so wird aus einem Int64 Array ein Word Array (16 Bit sollten reichen, oder wird ein Abstand>65535 bei zahlen bis 16x10^18 erreicht?).. vor der 3 wird die "2" jetzt als 1 Primzahl vorrausgesetzt (diese wird nicht errechnet sondern als bekannt vorgegeben)
ArrayIndex Inhalt
0................1
1................2
2................2
3................4
4................2
5................4
6................2
Gesamte Ersparnis (an Ram) ist abhängig von der Höhe der Primzahlen! in kleineren Bereichen gibt es viele Primzahlen und somit ist die Ersparnis hier gering (sogar negativ), in höheren Bereichen (wie 1 Milliarde) ist nur noch durchschnittlich jede 20te zahl eine Primzahl, da allerdings aus 1 Bit (boolean) zu 16 bits (word) werden, ist auch hier die Ersparnis gering ca 20% des gesamten Arbeitsspeichers
(Berechnung bis ca 42 Mrd. maximal möglich! bei "normaler" Auslastung nur bis 33 Mrd)
Und durch die 1ste Optimierung fällt kaum Rechenzeit hinzu, hier hingegen eine Beträchtliche kürzungszeit.. deshalb ist es fraglich die 2te Optimierung überhaupt durchzuführen
Gerd Kayser - Di 23.04.13 20:54
IhopeonlyReader hat folgendes geschrieben : |
also bis 13,7 Milliarden, da ist bei mir Schluss.. so ist selbst bei Vollausnutzung (2GB) der Maximalwert bei 17,18 Mrd erreicht... (abgesehen davon, dass solche abgespeicherten Primzahlen.txt s 10 B groß wären) ist mir das zu wenig... |
Wenn der Speicher zum Sieben nicht reicht, kann man auch eine Datei auf der Festplatte dazu verwenden. Bei einer Größe von z. B. 250 GB kannst Du die Zahlen bis zu zwei Billionen untersuchen. Bei größeren Dateien entsprechend mehr. Um die Festplattenzugriffe etwas zu reduzieren, kann man die Datei mit vorgesiebten Werten initialisieren (Primzahlen 2, 3, 5, 7). Je mehr Primzahlen, desto weniger Festplattenzugriffe, desto schneller. Danach die Primzahldatei auswerten (Primzahlen als Klartext in eine Textdatei wegschreiben und die riesige Datei wieder löschen).
IhopeonlyReader - Di 23.04.13 21:32
An Festplattenausweichung habe ich auch schon gedacht.. aber das würde das ganze natürlich nocheinmal EXTREM verlangsamen...
Aber eine Möglichkeit wäre es natürlich :)... würdest du mir allerdings helfen, wie ich eine Datei auf die Festplatte auslagere?
Nachtrag:
Gerd Kayser hat folgendes geschrieben : |
z. B. 250 GB kannst Du die Zahlen bis zu zwei Billionen untersuchen |
sogar bis und 250(Festplatte)*2(weil ich nur ungerade zahlen verwenden werde)*1024^3(GB->B)*8(Bit pro Byte) = 250*2*1024^3 *8 = 2^32 *10^3 (ca 4Billionen)
da eine Festplatte (HDD) allerdings nur 1/1000 bit(oder Byte?!)/s liest, würde dies aber schon bis 1 Milliarde ca. 10Min dauern (antatt max. 1min)
Gerd Kayser - 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 - 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..
Gerd Kayser - 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 - 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?
Gerd Kayser - 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 - 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 :D): 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])); |
Gerd Kayser - 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:
|
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:
http://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 - 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 - 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: http://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)
Gerd Kayser - 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.
IhopeonlyReader - 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
Mr_Emre_D - 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..
Mr_Emre_D - 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.
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: 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. |
Mathematiker - 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
http://www.entwickler-ecke.de/viewtopic.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
Mr_Emre_D - 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 - Do 09.05.13 01:59
[doppelpost]
IhopeonlyReader - 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
Mr_Emre_D - 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 - Do 09.05.13 20:51
Zur Auslagerung auf die HDD sollte man evtl. MMF's verwenden.
Horst_H - 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 [
http://www.entwickler-ecke.de/download.php?id=15834] 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
BenBE - Do 16.05.13 16:00
Für solche Aufgaben, bei denen große Datenmengen verwaltet werden müsen, gibt es schon seit Ewigkeiten Memory Mapped Files. Wenn man jeweils mit 1MB-Windows arbeitet und diese möglichst lange offen halten kann (oder sequentiell das nächste öffnet), dann kann man da sehr viel Performance rausholen und wird vom OS sogar noch durch Read-Ahead und andere Späße unterstützt. Und dank NTFS sind auch Datenmengen bis 16EiB in den RAM zu mappen kein Thema. Nur Windows ist derzeit da auf 16TB limitiert, was aber dennoch knapp 128 * 2^40 Zahlen sind. Sollte also für den Anfang reichen ;-)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!