Floating-point pression Platform abhängies EPSILON



  • Hallo Leute,

    ich schreibe gerade ein paar Geometry funktione in C(89). Je nach Plattform Addressbreite muss die double precision für die compare-funktion eine ELIPSON erstellen.

    https://en.wikipedia.org/wiki/Machine_epsilon

    Gibt es ne Möglichkeit dass diese automatisch je nach platform erstellt wird?

    Danke dir



  • @SoIntMan In <float.h> gibt es ein paar Angaben, die dafür gedacht sind.



  • @DirkB sagte in Floating-point pression Platform abhängies EPSILON:

    <float.h>

    Herzilchen Dank, aber muss ich da nun mit sizeof(double) checken wie groß die addressbreite is?



  • Der Header definiert u.a. die Makros FLT_EPSILON, DBL_EPSILON.

    Das folgende Programm ist zwar C++, aber die Informationen die ausgelesen werden sind dieselben.

    #include <iostream>
    #include <iomanip>
    #include <cfloat>
    
    using namespace std;
    
    int main () {
        cout << "FLT_RADIX " << FLT_RADIX << "\n\n";
        cout << scientific;
        cout << "float       size: " << setw(2) << sizeof(float)       << " digits: " << setw(3) <<  FLT_MANT_DIG << " min exp: " << setw(6) <<  FLT_MIN_EXP << " max exp: " << setw(5) <<  FLT_MAX_EXP << " epsilon: " <<  FLT_EPSILON << "\n";
        cout << "double      size: " << setw(2) << sizeof(double)      << " digits: " << setw(3) <<  DBL_MANT_DIG << " min exp: " << setw(6) <<  DBL_MIN_EXP << " max exp: " << setw(5) <<  DBL_MAX_EXP << " epsilon: " <<  DBL_EPSILON << "\n";
        cout << "long double size: " << setw(2) << sizeof(long double) << " digits: " << setw(3) << LDBL_MANT_DIG << " min exp: " << setw(6) << LDBL_MIN_EXP << " max exp: " << setw(5) << LDBL_MAX_EXP << " epsilon: ";
    
        double eps = LDBL_EPSILON;
    
        cout << eps << "\n";
    }
    
    


  • @john-0 super danke dir für die mühe;)



  • @SoIntMan sagte in Floating-point pression Platform abhängies EPSILON:

    Herzilchen Dank, aber muss ich da nun mit sizeof(double) checken wie groß die addressbreite is?

    Die Adressbreite hat nichts mit der Auflösung von float oder double zu tun.

    Mit `sizeof(double) bekommst du den Speicherverbrauch. Mit den Makros aus float.h den Wertebereich und Auflösung.

    Die Adressbreite wäre sizeof(double*) oder besser sizeof(void*). Das ist aber was ganz anderes


  • Mod

    Das Maschinenepsilon für Vergleiche nutzen zu wollen, heißt, dass man nicht verstanden hat, was das Maschinenepsilon ist. Was wenn die Werte nicht in der Größenordnung von 1 liegen? Was die Hauptattraktion von Fließkommazahlen ist, dass sie beliebige Größenordnungen darstellen können. Und selbst wenn sie in der Größenordnung von 1 liegen, was ist dann das besondere an dem Epsilonwert? Es mag 1.0 + epsilon != 1.0 sein, aber für jeden anderen Wert statt 1.0 braucht das nicht mehr zu gelten.

    Übliche Vorgehensweise: Die Fließkommazahlen als Integer interpretieren. Die Differenz zwischen den Integern entspricht dann gerade genau der Anzahl Fließkommawerte die zwischen den beiden Fließkommazahlen liegen. Da kann man sich dann aussuchen, wie viele man da erlauben möchte. Das setzt natürlich eine interne Repräsentation nach IEEE 754 und eine übliche interne Integerrepräsentation voraus, aber von beidem kann man eigentlich ausgehen.



  • @SeppJ sagte in Floating-point pression Platform abhängies EPSILON:

    … was ist dann das besondere an dem Epsilonwert? …

    Das Epsilon gibt an wie genau die Auflösung der Mantisse ist. Man braucht für bestimmte Rechnungen eine entsprechend breite Mantisse, damit es eben nicht zur numerischen Auslöschung kommt. Ggf. ist die DBL_MANT_DIG und DBL_DIG (bzw, FLT_ .…) sinnvoller, weil man darüber das gleich sehen kann. Selbstredend taugt das nichts, um Gleitkommazahlen auf Gleichheit zu vergleichen.
    @SoIntMan sagte in Floating-point pression Platform abhängies EPSILON:

    @john-0 super danke dir für die mühe;)

    Das Programm existierte bereits.



  • @DirkB sagte in Floating-point pression Platform abhängies EPSILON:

    Die Adressbreite hat nichts mit der Auflösung von float oder double zu tun.
    Mit `sizeof(double) bekommst du den Speicherverbrauch. Mit den Makros aus float.h den Wertebereich und Auflösung.
    Die Adressbreite wäre sizeof(double*) oder besser sizeof(void*). Das ist aber was ganz anderes

    Guten Morge Dirk, ja das habe ich gerade herausgefunden, dass float (immer) 4byte ist und double(immer) 8 byte, ..was bedeutet, dass auf einem 32bit System die double Berechnung rechen intensiver sein werden nehme ich an.!?
    Das war mir nicht bewusst, weil ich wie bei integer davon ausging dass das die breite vom addressbreite abhängt.. 🙂

    @SeppJ sagte in Floating-point pression Platform abhängies EPSILON:

    Das Maschinenepsilon für Vergleiche nutzen zu wollen, heißt, dass man nicht verstanden hat, was das Maschinenepsilon ist.

    Nein hab ich wirklich nicht verstanden, würde ich aber gerne:)

    Sin(90) was exakt 1 ergibt, aber er mir 0.99999999999999989 auspuckt.
    Cos(90) was exakt 0 ergibt, ab er er mir 1.2246467991473532E-16 auspuckt

    wenn ich nun prüfen will ob Cos(90) == 0 ist , dann braucht ich as Machien eplison!?!? ist das ein gutes beispiel?



  • @SoIntMan sagte in Floating-point pression Platform abhängies EPSILON:

    wenn ich nun prüfen will ob Cos(90) == 0 ist , dann braucht ich as Machien eplison!?!? ist das ein gutes beispiel?

    Das ist ein schlechtes Beispiel, da dafür das Epsilon nicht gedacht ist. Wenn man rechnet, dann entsteht immer ein Fehler in der Berechnung mit Gleitkommazahlen und dieser pflanzt sich durch die Berechnungen fort. Im Fall von cos(pi/2) könntest Du gerade Glück haben, wenn die cos exakt genug implementiert ist. Man darf aber nicht davon ausgehen, dass cos(pi/2) nur um Epsilon von wahren Wert abweicht.

    Sinnvoll wäre es daher cos(pi/2) < akzeptabler_fehler zu prüfen.



  • @SoIntMan sagte in Floating-point pression Platform abhängies EPSILON:

    Guten Morge Dirk, ja das habe ich gerade herausgefunden, dass float (immer) 4byte ist und double(immer) 8 byte, ..

    Diese Annahme ist - für C89 - falsch. Das ist sehr sehr häufig der Fall, aber nicht garantiert.

    was bedeutet, dass auf einem 32bit System die double Berechnung rechen intensiver sein werden nehme ich an.!?

    Rechenintensiver nicht unbedingt, da es auch Fließkommaprozessoren gibt. Es sagt auch nichts über die Anbindung des Speichers aus (wie oft muss für die Daten auf den Speicher zugegriffen werden).

    Das war mir nicht bewusst, weil ich wie bei integer davon ausging dass das die breite vom addressbreite abhängt..

    Du vermixt da auch Adressen und Daten.

    Die Bitbreite sagt ewas über die Daten aus. Dies muss aber nicht mit dem der Adressen übereinstimmen. Die besagt nur, wieviel Speicher maximal adressierbar ist.



  • @SoIntMan sagte in Floating-point pression Platform abhängies EPSILON:

    wenn ich nun prüfen will ob Cos(90) == 0 ist , dann braucht ich as Machien eplison!?!? ist das ein gutes beispiel?

    Du brauchst ein Epsilon für genau den Anwendungsfall den du gerade hast.

    Fließkommazahlen haben (in Dezimaldarstellung) das Format Mantisse x 10^Exponent (^steht für hoch)
    Die Anzahl der Stellen von Mantisse und Exponent sind begrenzt und legen die Genauigkeit und den Wertebereich fest.

    123456 kann man als 1,23456 x 10^6 schreiben. Wenn aber die MAntisse nur 4 Stellen zulässt, dann hast du nur 1,234 x 10^6 was dann 123400 ist oder 123500 (als nächst höhere Zahl).
    Da ist das Epsilon mindestens 100.

    Das gilt umgekehrt für kleiner Zahlen und der Rechner macht das im Binärsystem.

    Wenn du damit spielen willst, kannst du mal bei https://www.h-schmidt.net/FloatConverter/IEEE754.html vorbei schauen.



  • @john-0 sagte in Floating-point pression Platform abhängies EPSILON:

    Das ist ein schlechtes Beispiel, da dafür das Epsilon nicht gedacht ist. Wenn man rechnet, dann entsteht immer ein Fehler in der Berechnung mit Gleitkommazahlen und dieser pflanzt sich durch die Berechnungen fort. Im Fall von cos(pi/2) könntest Du gerade Glück haben, wenn die cos exakt genug implementiert ist. Man darf aber nicht davon ausgehen, dass cos(pi/2) nur um Epsilon von wahren Wert abweicht.
    Sinnvoll wäre es daher cos(pi/2) < akzeptabler_fehler zu prüfen.

    Ok danke für deine Ausführung. Jetzt habe ich hier ein Konkreter fall. Ich möchte die höhe und breite eine rotierten rechtecks berechnen. geben is das äußere rechteck und der rotations winkel. siehe

    https://stackoverflow.com/questions/9971230/calculate-rotated-rectangle-size-from-known-bounding-box-coordinates

    hier ergibt sich folgendes:

    x = (1/(cos(t)^2-sin(t)^2)) * ( bx * cos(t) - by * sin(t)) 
    y = (1/(cos(t)^2-sin(t)^2)) * (- bx * sin(t) + by * cos(t))
    

    Angenommen t = 45°, bx =100, by =100

    da is (cos(t)^2 - sin(t)^2)) == 0 bzw 1/0 =NaN aber ich vermute das wird ne Ausnahme sein.. weil bei != 45 bekomme ich richtige Ergebnisse...

    aber das hat dann nicht mit EPLISION zu tun, außer (cos(t)^2 - sin(t)^2)) nähringweise 0 dann kommt bei 1/x ne rießen zahl raus..

    Sorry ich denke gerade Laut;)



  • @SoIntMan sagte in Floating-point pression Platform abhängies EPSILON:

    Angenommen t = 45°, bx =100, by =100

    Die Winkelfunktionen in C verlangen nach Winkel im Bogenmaß (Vollkreis ist 2π2\pi), hast Du so die Werte übergeben?



  • @SoIntMan Du kannst da auf das NaN reagieren.

    https://de.wikipedia.org/wiki/NaN

    Da das nur bei 45° +/- n*90° auftritt, kannst du dann den Sonderfall behandeln



  • @john-0 jepp habe ich

    public double ConvertToRadians(double angle)
    {
        return (Math.PI / 180) * angle;
    }
    

    🙂





  • @DirkB sagte in Floating-point pression Platform abhängies EPSILON:

    @SoIntMan Du kannst da auf das NaN reagieren.
    https://de.wikipedia.org/wiki/NaN
    Da das nur bei 45° +/- n*90° auftritt, kannst du dann den Sonderfall behandeln

    vielen dank;) solangsam wirds;)


  • Mod

    Da hier anscheinend nicht verstanden wird, warum Maschinenepsilon absolut gar nix mit Gleichheit zu tun hat eine Demo (ich spare mir mal eine saubere Templatisierung, die die Bitbreite der Fleißkommazahlen und Integers betrachtet und nehme an sizeof(double) == sizeof(long)):

    #include<iostream>
    #include<iomanip>
    #include<cfloat>
    
    using namespace std;
    
    void print_diff(double lhs, double rhs)
    {
      int diff = *(long*)&lhs - *(long*)&rhs;
      cout << setprecision(20) << lhs<< " ist um " <<  diff << " Fließkommawerte größer als " << rhs << ". Absolute Differenz ist " << lhs - rhs << '\n';
    
    }
    
    int main()
    {
      cout << "Maschinenepsilon: " << DBL_EPSILON << '\n';
    	
      double literal_one = 1.0;
      double calculated_one = 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1;
      print_diff(literal_one, calculated_one);
    
      double literal_large_value = 1e50;
      double calculated_large_value = calculated_one * 1e50;
      print_diff(literal_large_value, calculated_large_value);
    
      double literal_small_value = 1e-50;
      double calculated_small_value = calculated_one * 1e-50;
      print_diff(literal_small_value, calculated_small_value);
    }
    

    Ausgabe auf den meisten Systemen:

    Maschinenepsilon: 2.22045e-16
    1 ist um 1 Fließkommawerte größer als 0.99999999999999988898. Absolute Differenz ist 1.1102230246251565404e-16
    1.0000000000000000763e+50 ist um 1 Fließkommawerte größer als 9.9999999999999986861e+49. Absolute Differenz ist 2.0769187434139310514e+34
    1.0000000000000000076e-50 ist um 1 Fließkommawerte größer als 9.9999999999999988892e-51. Absolute Differenz ist 1.1869459682199748434e-66
    

    Wenn jemand erklären möchte, wieso die Zahl 2.22045e-16 irgendetwas damit zu tun haben sollte, dass zwei Werte, die sich um 1.1e-16; 2.1e34; oder 1.2e-66 unterscheiden, trotzdem praktisch gleich sind, dann nur zu! Ich war ja sogar so nett und habe beim ersten Beispiel den Wert 1.0 zum Vergleich genommen, der direkt in der Definition des Epsilon vorkommt, bin aber bloß nach unten abgewichen. Und schon ist die Differenz ein ganz anderer Wert als Epsilon!



  • @SeppJ sagte in Floating-point pression Platform abhängies EPSILON:

    Wenn jemand erklären möchte, wieso die Zahl 2.22045e-16 irgendetwas damit zu tun haben sollte, dass zwei Werte, die sich um 1.1e-16; 2.1e34; oder 1.2e-66 unterscheiden, trotzdem praktisch gleich sind, dann nur zu!

    Wenn du das Maschinenepsilon mit dem betragsmässig grösseren der beiden Summanden multiplizierst, bekommst du eine gute Abschätzung für den maximal möglichen Fehler.


Anmelden zum Antworten