long double Zufallswerte


  • Mod

    fuse schrieb:

    Ergäbe sich eine Wahrscheinlichkeitsverschiebung,
    wenn ich Zufallsfunktionsergebnisse aufaddiere bis die maximalen Zufallszahlen
    den kompletten Zahlenraum füllen würden ?

    Ja, das geht dann gegen eine Gaußverteilung.

    Außerdem kannst du nicht beliebig integer-Werte zu einem double addieren, denn schon bald wird der gespeicherte Wert so groß, dass eine Addition eines INT_MAX trotzdem wieder den alten Wert ergibt.

    Bei long double vom Minimalwert zum Maximalwert zu zählen stelle ich mir Zeitaufwendig vor.

    Ähem, selbst wenn es theoretisch ginge (siehe oben, warum es nicht geht), bräuchtest du etwa 10^4913 Rechenschritte. Du bräuchtest mit jetziger Technik etwa 10^4897 CPU-Jahre dafür.

    Der long double ist auch nur um die 16 Byte groß. Nur die Interpretation ist anders als z.B. bei einem long int. Das heißt es gibt 2^16 mögliche Werte die ein double annehmen kann. Wenn du es so machst wie in diesem Thread gezeigt und einfach ein zufälliges 16 Byte Bitmuster reinterpretierst, dann hast du die möglichen Werte eines double gleichmäßig abgedeckt. Dabei willst du wahrscheinlich auch noch Sonderwerte wie inf und NaN abfangen.
    Wenn es das ist, was du willst (was nichts anderes ist als eine 16 Byte Zufallszahl), dann mach es. Die Werte sind dann aber nicht gleichmäßig auf den reellen Zahlenraum verteilt. Angefangen damit, dass es zum Beispiel zwei verschiedene Nullen gibt, entspricht die Dichteverteilung der Zufallszahlen ungefähr so wie |1/x| aus*. Falls die Gleichverteilung über einen so großen Zahlenbereich wichtig sein sollte, ist double der falsche Typ.

    *: Ja, es ist nicht |1/x|, weil das keine gültige dichtefunktion ist, aber es sieht so ähnlich aus und ich war zu faul zum Rechnen was es genau ist. Die Funktion |1/x| illustriert das Problem ganz gut.



  • Wenn es einen Datentyp mit einer ähnlichen Präzision gibt,
    ist er vermutlich auch geeignet.

    Beim Aufadieren würde ich das Komma durch teilen nachrücken.

    Die beschrieben Lösung probiere ich gern aus.

    Methode:

    void TForm1::ZufallsgeneratorLongDouble1(double& number)
    {
    while((number < -1.1E-4932l) || IsNan(number) || IsInfinite(number))
      {
      for(unsigned int i = 0; i != sizeof(long double); ++i)
        *reinterpret_cast<unsigned char*>(&number) = (unsigned char)rand();
      }
    }
    //---------------------------------------------------------------------------
    

    Aufruf:

    ZufallsgeneratorLongDouble1(verbindung[netz][quellschicht][verbindungsquelle][verbindungsziel]);     // gewichtung   // geringster wert: -3.4E-4932l nicht genutzt um ein symetrisches verhältnis zu erzeugen
    

    Fehlermeldung:
    ---------------------------
    Benachrichtigung über Debugger-Exception
    ---------------------------
    Im Projekt NNTwo.exe ist eine Exception der Klasse EOverflow aufgetreten. Meldung: 'Gleitkommaüberlauf'. Prozeß wurde angehalten. Mit Einzelne Anweisung oder Start fortsetzen.
    ---------------------------
    OK Hilfe
    ---------------------------

    Was müßte geändert werden ?



  • fuse schrieb:

    Methode:

    void TForm1::ZufallsgeneratorLongDouble1(double& number)
    {
    while((number < -1.1E-4932l) || IsNan(number) || IsInfinite(number))
      {
      for(unsigned int i = 0; i != sizeof(long double); ++i)
        *reinterpret_cast<unsigned char*>(&number) = (unsigned char)rand();
      }
    }
    

    Was müßte geändert werden ?

    alles 😋



  • Welchen Code ergibt die vorgeschlagene Änderung ?



  • fuse schrieb:

    für die Startwerte der Gewichtungen meines neuralen Backpropergation Netzes
    hätte ich gern den Code eines geeigneten Zufallsgenerators.

    Er soll schnell sein
    und möglichst zufällige sowie gleichmäßig verteilte Fließkommazahlen
    im Wertebereich -1,1E-4932 bis 1,1E4932 zurückgeben.

    😮

    Für die Gewichte eines solchen Netzes würde ich mich auf einen viel kleineren Zahlenbereich beschränken, zB so etwas:

    /// liefert Zufallszahl zwischen 0...1
    double rectangularPDF();
    
    /// liefert Zufallszahl zwischen -1...1
    double triangularPDF()
    {
      double t = rectangularPDF();
      t -= rectangularPDF();
      return t;
    }
    
      ...
      gewicht = triangularPDF() * 10;
      ...
    

    (oder so)



  • Das ist auch interessant
    und wenn sich der Überlauf bei der ersten Lösung vermeiden lässt
    gäbe es schon 2 Lösungsansätze.



  • SeppJ schrieb:

    Der long double ist auch nur um die 16 Byte groß. Nur die Interpretation ist anders als z.B. bei einem long int. Das heißt es gibt 2^16 mögliche Werte die ein double annehmen kann.

    2^128. (Byte != Bit)

    Dementsprechend braucht man, um von einem Ende zum nächsten zu zählen, auch nur etwa etwa 10^38,5 Schritte. Das ist auch eines der Probleme, in das man mit einer Gleichverteilung über einen derart großen Bereich in Fließkommazahlen läuft - Wenn du einem long double 1,1e-4932 zuweist und eins draufzählst, ändert sich der Wert nicht, weil der Datentyp nicht genau genug ist, beide Werte darzustellen.

    Aus diesem Grund generiert man Fließkommazufallswerte üblicherweise zwischen 0 und 1, wo der Exponent keine Rolle spielt, und multipliziert dann ggf. mit der gewünschten Bereichsgröße, nach dem Muster

    (double) rand() / RAND_MAX
    

    Um das ganze zu erweitern, wäre eine Reihenentwicklung wahrscheinlich das einfachste. Ich stelle mir das etwa so vor:

    long double float_rand() {
      static long double const precise_max = std::pow(2.0L, std::numeric_limits<long double>::digits) - 1;
      static long double const rand_mod = RAND_MAX + 1.0L;
    
      long double x = 0;
      long double divisor = 1;
    
      do {
        x = x * rand_mod + rand();
        divisor *= rand_mod;
      } while(divisor < precise_max / rand_mod);
    
      x = x * (precise_max / divisor) + (rand() / precise_max * divisor);
    
      return x / precise_max;
    }
    


  • seldon schrieb:

    Aus diesem Grund generiert man Fließkommazufallswerte üblicherweise zwischen 0 und 1, wo der Exponent keine Rolle spielt, und multipliziert dann ggf. mit der gewünschten Bereichsgröße, nach dem Muster

    (double) rand() / RAND_MAX
    

    Du meinst

    Nexus (1. Antwort) schrieb:

    long double Random(long double begin, long double end)
    {
        return static_cast<long double>(rand()) / RAND_MAX * (end - begin) + begin;
    }
    

    😉



  • Welche Schrittweite zwischen 1 und -1 ist am kleinsten, ändert den Wert aber noch ?



  • Für den long double Datentyp verwendet der Borlnd C++ Compiler 80 Bit.



  • fuse schrieb:

    Er soll schnell sein
    und möglichst zufällige sowie gleichmäßig verteilte Fließkommazahlen
    im Wertebereich -1,1E-4932 bis 1,1E4932 zurückgeben.

    Interessante Frage,
    für ein neuronales Netz würde ich dir persönlich allerdings kleine Werte bevorzugen wie z.B. zwischen
    -1 und 1 empfehlen oder -0,5 und 0,5

    EDIT: Beim vollen Ausschöpfen des Wertebereichs kriegst du auch noch Probleme mit Überläufen... Inwiefern sie die Leistungsfähigkeit deines Netzes beeinflussen, vermag ich jetzt nicht zu beurteilen



  • Ich beabsichtige meine Wertigkeit nun zwischen 1 und -1 zu legen
    und möchte noch die Schrittweite für long double herrausfinden.
    Anhand des Aufbaus lässt sich das wahrscheinlich ausrechnen.

    Auch wenn long double nicht dem Standard entspriicht
    würde ich zunächst gern daran festhalten, da das Netz dann vermutlich auch gut
    mit kleinen Unterschieden zwischen hochauflösenden Bildern umgehen kann.


  • Mod

    fuse schrieb:

    Ich beabsichtige meine Wertigkeit nun zwischen 1 und -1 zu legen
    und möchte noch die Schrittweite für long double herrausfinden.
    Anhand des Aufbaus lässt sich das wahrscheinlich ausrechnen.

    Auch wenn long double nicht dem Standard entspriicht
    würde ich zunächst gern daran festhalten, da das Netz dann vermutlich auch gut
    mit kleinen Unterschieden zwischen hochauflösenden Bildern umgehen kann.

    Die Auflösung in der Gegend von 1 ist wiederum das epsilon von dem Typen (herauszufinden mit numeric_limits). Nach wie vor gilt jedoch, dass die Auflösung sich mit dem Wert ändert, nahe Null ist die Auflösung viel feiner, bis hin zu 1*(2 hoch min_exponent). Wenn du tatsächlich einfach nur zufällige Bitmuster im double erzeugst, musst du dies beachten. Die Verteilung müsste dann logarithmisch sein.


Anmelden zum Antworten