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

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
Laut Profil Delphi 7
Richtig :)
user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
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,
user profile iconTranx hat folgendes geschrieben Zum zitierten Posting springen:
... 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;

//Array setzten
setlength( BoolArray, 1000000 );
//Bool auslesen
if BoolArray[X] then //...
//Bool setzten
if BoolArray[X] then BoolArray[X] := False; // Die if Abfrage vorher, da es sein kann dass es schon False ist und schreiben wesentlich länger dauert als lesen


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//Größe des Speichers (SizeOf(Byte)*8)  .. so ist schneller wechsel auf z.B: Integer (32) möglich 
 
//Array setzen
setlength( BitBoolArray , 1000000 div Size +1); //Da ein Byte (8Bit) ja 8 Booleans fasst

//Bool auslesen
if GibBoolean(X) then //...
//Bool setzten
SetzteBool(X, False); //Keine if Abfrage, da schon in SetzteBoolean vorhanden

//einzelnen Funktionen:

Function GibBoolean(Zahl: Integer): Boolean;
var Z, CopyOfFeld: Byte;
begin
CopyOfFeld := BitBoolArray [Zahl div Size];
Result := False;
For Z:=(Size-1downto (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 // Da Boolean <> Boolean ist (False<>False z.B. 255 und 13) frage ich sicherheitshalber einzeln ab und nicht if Wert<>GibBoolean(Zahl)
  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;//= 1 shl 5 = 32
  BITMASKE = 31;//= 1 shl BITPOS-1;
type
  tBoolSet = set of 0..BITMASKE; // 0.. 1 shl BITPOS-1 ;
  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
  //BitNr = Zahl AND BITMASKE;Index := Zahl SHR BITPOS;
  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;
  // Wieviel 32 Bit set werden gebraucht bei 1..32 -> 1; 33..64-> 2.
  ArrSize =(ArrBitSize+BITMASKE) SHR BITPOS;
var
  T1,T0: TDatetime;
  i : LongInt;

BEGIN
  setlength(bA,ArrSize);
  T0 := now;
  // Alle Bit setzen
  For i:= 1 to ArrBitSize do
    SetzeBoolean(i,true);
  // Test ob auch alles richtig war, keiner darf nicht gesetzt sein
  For i:= 1 to ArrBitSize do
    IF NOT(GibBoolean(i)) then
      writeln('Fehler bei: ',i);

  // Alle Bit loeschen
  For i:= 1 to ArrBitSize do
    SetzeBoolean(i,false);
  // Test ob auch alles richtig war, keiner darf gesetzt sein
  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

user profile iconjfheins hat folgendes geschrieben Zum zitierten Posting springen:
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;

//Initialisieren mit
 For C:=0 to High(BitBoolArray) do
     BitBoolArray[C] := round(power(2, Size)-1); //geht wesentlich schneller als alle einzeln durchzugehen und auf true zu setzen


Und: @Mr_Emre.. soweit sind wir schon dank Gerd Kayser :).. aber ich denke deshalb hast du auch
user profile iconMr_Emre_D hat folgendes geschrieben Zum zitierten Posting springen:
--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

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
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,
user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Zumindest gibt es erste Kandidaten für eine solche Lücke: 32769! (hier ist Fakultät gemeint) und ff.

Vollkommen richtig.
user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:

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,
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:

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..1000of 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<1001and (abstand[z]=0then
      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,
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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.
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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 user profile iconGammatester 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: user profile iconHorst_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,

@user profile iconMathematiker:
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,
user profile iconHorst_H hat folgendes geschrieben Zum zitierten Posting springen:
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.
user profile iconHorst_H hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:

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

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
18% schneller

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

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconGerd Kayser hat folgendes geschrieben Zum zitierten Posting springen:

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

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:

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,
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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?


Horst_H - Di 23.04.13 09:47

Hallo,

schade das user profile iconGammatester mit seinem Primepi32 nur bis Longint kommt.
http://www.entwickler-ecke.de/viewtopic.php?t=109633&postorder=asc&highlight=enumeration&start=20 und in seiner Multipräzisions-Arithmetik [http://www.wolfgang-ehrhardt.de/misc_de.html#mparith] integriert.
Das müßte sich doch auf 64-Bit erweitern lassen.

Gruß Horst


Gammatester - Di 23.04.13 10:39

user profile iconHorst_H hat folgendes geschrieben Zum zitierten Posting springen:
Das müßte sich doch auf 64-Bit erweitern lassen.
Ja es läßt sich auf 64-Bit erweitern (die Hauptbremse wäre die Legendre-Funktion lsumphi), obwohl wahrscheinlich die Rechenzeit dramatisch ansteigen wird, 'execution time balloons to several hours near 1e15 or 1e16' wie Thomas R. Nicely [http://www.trnicely.net/#PIX4] für seinen C-Code schreibt.

In der Zwischenzeit (bis Horst_H das optimiert hat :wink:), kann man statt Li(x) die Funktion RiemannR(x) aus meinen Speziellen-Funktionen [http://www.wolfgang-ehrhardt.de/misc_de.html#specfun_units] benutzen, die etwas bessere Werte liefert, zB für x=12e9: Mathematiker-Sieb 541555852, RiemannR 541556725, Li 541562075.

Gruß Gammatester

Edit: Bevor die Beiträge eh zusammengefaß werden:
user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Nachtrag: Ich habe 541555852 beim exakten Sieben gezählt. Ist bei Dir die 2 dabei?
Dann haben Du bzw. Dein Sieb sich wohl verzählt, denn http://www.primefan.ru/stuff/primes/10(07)11.txt und Wolfram Alpha [http://www.wolframalpha.com/input/?i=PrimePi(12000000000)] sagen PrimePi(12E9) = 541555851


IhopeonlyReader - Di 23.04.13 13:22

user profile iconMathematiker 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 user profile iconGammatester :), 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 user profile iconGammatester 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)
user profile iconHorst_H hat folgendes geschrieben Zum zitierten Posting springen:

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// [Fehler] prime_pi.dpr(21): Überlauf bei Konvertierung oder arithmetischer Operation
{also:} testnum = 12000000000// ist dasselbe, gibt kein fehler aus
//und
 Primes1E6 : array[1..NumPrimes1E6+8of DWord; //funktioniert nicht
DWord = LongWord // DWord existiert in Delphi7 nicht ?° also
 Primes1E6 : array[1..NumPrimes1E6+8of LongWord;
//und
c := Primes1E6Index(trunc(exp(ln(x)/3.0)+0.5)); //funktioniert nicht, da ln nur mit real zahlen rechnet, x aber int64 ist... also
c := Primes1E6Index(trunc(exp(ln(x/1)/3.0)+0.5)); (ln(x/1); //hier wird automatisch gecastet... sinnlos aber funktioniert^^


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 user profile iconGammatester 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

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
@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:
user profile iconHorst_H hat folgendes geschrieben Zum zitierten Posting springen:
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:

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:

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.
user profile iconTranx hat folgendes geschrieben Zum zitierten Posting springen:
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,
user profile iconjfheins hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:

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

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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:

user profile iconGerd Kayser hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconGerd Kayser hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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;  // int64 nicht möglich
  ZahlByte   : byte;
  Zahl       : cardinal;
  FS         : TFileStream;
  DatenBlock : array [0..124999of byte; // 125.000 Bytes = 1 Mio. Bits bzw. Zahlen
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   // = 10 Mrd. Bytes große Datei (= 80 Mrd. Bits / Zahlen)
      FS.Write(DatenBlock, SizeOf(DatenBlock));
    FS.Position := 0;                    // zurück zum Anfang
    FS.Read(ZahlByte, SizeOf(ZahlByte)); // nur ein Byte lesen
    ZahlByte := ZahlByte xor $03;        // 1 keine Primzahl, 2 = Primzahl
    FS.Position := 0;         // Durch das Lesen wurde der Zeiger verschoben.
    FS.Write(ZahlByte, SizeOf(ZahlByte));
      // Kleiner Test, um das Endian-Problem zu verdeutlichen.
    FS.Position := 10;        // Durch das Schreiben wurde der Zeiger verschoben.
                              // Wird hier willkürlich auf 10 (= 11. Byte) gesetzt.
    Zahl := $12345678;        // Im Hex-Editor mal die Bytes ansehen. (siehe Endian)
    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

user profile iconGerd Kayser hat folgendes geschrieben Zum zitierten Posting springen:

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   // = 10 Mrd. Bytes große Datei (= 80 Mrd. Bits / Zahlen)                    

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]); //WriteBuffer oder Write?
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:
{Type TSavedDataBlocks = record
 Pfad: String; //fester Pfad + '\' + IntToStr(BlockNr);
 Anzahl: Cardinal
end;
var GespBloecke: Array of TSavedDataBlocks;}


setlength(DatenBlock, Gesp[BlockNr].Anzahl);
For Schleife:=High(DatenBlock) downto 1 do // von hinten nach vorn, wie du oben sagtest ist richtig oder?
  FS.ReadBuffer(DatenBlock[Schleife], SizeOf(DatenBlock[Schleife])); //ReadBuffer oder Read ? ich kenns mit Buffer...


Gerd Kayser - Do 25.04.13 01:00

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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]); //WriteBuffer oder Write?
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:
{Type TSavedDataBlocks = record
 Pfad: String; //fester Pfad + '\' + IntToStr(BlockNr);
 Anzahl: Cardinal
end; 
var GespBloecke: Array of TSavedDataBlocks;}

Wozu???

Zitat:

Delphi-Quelltext
1:
2:
3:
setlength(DatenBlock, Gesp[BlockNr].Anzahl);
For Schleife:=High(DatenBlock) downto 1 do // von hinten nach vorn, wie du oben sagtest ist richtig oder?
  FS.ReadBuffer(DatenBlock[Schleife], SizeOf(DatenBlock[Schleife])); //ReadBuffer oder Read ? ich kenns mit Buffer...

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

user profile iconGerd Kayser hat folgendes geschrieben Zum zitierten Posting springen:

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 ...

user profile iconGerd Kayser hat folgendes geschrieben Zum zitierten Posting springen:

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


user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:
Vielleicht liest es ja noch jemand:

Ja^^
user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:

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

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
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 user profile iconGerd 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;

// Lots Of Primes
// mr_emre_d
// @ entwickler-ecke.de

{$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}

(*
** ExtendedSieveOfEratosthenes calculates primenumber in a given range
** the range is specified by [StartingNumber, Primes.Len*2]
** Primes.Len * 2 because the Primes Array only contains odd numbers (since even numbers cant be prime)
*)

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
    // fast-iterate to the beginning of the sieve
    if candidate < FromOffset then
    begin
      multiples := candidate * Round(FromOffset/candidate);
      if multiples < FromOffset then
        inc(multiples, candidate);
    end else
      multiples := candidate shl 1;

    // if the first multiple is already out of bounds we can stop sieving
    if multiples > ToOffset then break;

    // sieve
    while multiples <= ToOffset do
    begin
      // odd numbers only
      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;

    // ignore even numbers
    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);
//          Writeln(PrimeCount, '. ', (From + (p*8+q)*2));
        end;
//    Readln;
    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,
user profile iconMr_Emre_D hat folgendes geschrieben Zum zitierten Posting springen:
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 user profile iconHorst_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 user profile iconGammatester 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 ;-)