Fließkomma - Wie hole ich mehr Genauigkeit heraus?



  • KMT schrieb:

    Könnte gut sein, das die verschiedenen compiler es in unterschiedlicher Reihenfolge rechnen

    Siehe

    Athar schrieb:

    Die alte x87 FPU rechnet mit 80 Bit Genauigkeit. Wenn du für x86_64 kompilierst, dann werden die entsprechenden SSE-Befehle genommen, die mit 64 Bit Genauigkeit rechnen. Wenn du optimierst, dann rechnet gcc das schon zur Kompilierzeit zusammen - ebenfalls mit 64 Bit Genauigkeit. Deswegen bekommst du das "andere" Ergbnis nur bei x86 und ausgeschalteten Optimierungen.

    -3.01755e-20 liegt übrigens näher am realen Ergebnis.



  • Ah ok, übersehen.



  • Seien folgende Werte gegeben:
    
    w = -0.00161579
    rho = -3.23158e-05
    Igrad = 0.0004
    gamma = 0.02
    
    Weiter sei angenommen y = rho * gamma. Dann folgt:
    
    y = -3.23158e-05 * 0,02
      = -0,0000323158 * 0,02
      = -0
        -  0
        -   00000646216
        ---------------
        -0,000000646216
    
    Weiter sei angenommen z = y / Igrad. Dann folgt:
    
    z = -0,000000646216 / 0,0004
      = -0,000000646216 / (4/10000)
      = -0,000000646216 * (10000/4) 
      = -0,00646216 / 4
      = -0,00161554
    
    Weiter sei angenommen A = w - rho * gamma / Igrad. Dann folgt:
    
    A = w - rho * gamma / Igrad
      = w - y / Igrad
      = w - z
      = -0,00161579 - -0,00161554
      = -0,00161579 +  0,00161554
      = -0,00000025
    
    Damit folgt A != 0.
    

    Ferner gilt -0,00000025 < -2.16840434497101e-19 < -3.01755e-20.
    Dann gilt auch der das -2.16840434497101e-19 näher an der Wahrheit liegt wenn -0,00000025 die Wahrheit ist.



  • Du hast dich bei y verrechnet.



  • goran schrieb:

    Seien folgende Werte gegeben:
    
    w = -0.00161579
    rho = -3.23158e-05
    Igrad = 0.0004
    gamma = 0.02
    
    Weiter sei angenommen y = rho * gamma. Dann folgt:
    
    y = -3.23158e-05 * 0,02
      = -0,0000323158 * 0,02
      = -0
        -  0
        -   00000646216
        ---------------
        -0,000000646216
    
    Weiter sei angenommen z = y / Igrad. Dann folgt:
    
    z = -0,000000646216 / 0,0004
      = -0,000000646216 / (4/10000)
      = -0,000000646216 * (10000/4) 
      = -0,00646216 / 4
      = -0,00161554
    
    Weiter sei angenommen A = w - rho * gamma / Igrad. Dann folgt:
    
    A = w - rho * gamma / Igrad
      = w - y / Igrad
      = w - z
      = -0,00161579 - -0,00161554
      = -0,00161579 +  0,00161554
      = -0,00000025
    
    Damit folgt A != 0.
    

    Ferner gilt -0,00000025 < -2.16840434497101e-19 < -3.01755e-20.
    Dann gilt auch der das -2.16840434497101e-19 näher an der Wahrheit liegt wenn -0,00000025 die Wahrheit ist.

    😕



  • knivil schrieb:

    -3.01755e-20 ist doch vom Betrag her viel kleiner, also genauer.

    self quote ftw 🙂



  • Um nochmal auf die eigentliche Frage des TS zurückzukommen:

    Evtl. ist auch Intvallarithmetik für dich interessant, bei der berechnet wird, in welchem Intervall das Ergebnis garantiert liegt. Nach einer Bibliothek müsstest du selbst suchen.

    Ansonsten müsstest nach einer Klasse/Bibliothek suchen, die z.B. mit einer 256bit-Mantisse rechnet. Natürlich steigen dadurch die Rechenzeiten erheblich.



  • goran schrieb:

    folgendes Beispiel gibt -3.01755e-20 aus.

    int main() {
      double w = -0.00161579;
      double rho = -3.23158e-05;
      double Igrad = 0.0004;
      const double gamma = 0.02;
    
        w = w - rho * gamma / Igrad;
    
        std::cout << w << std::endl;
    }
    

    Das Ergebnis ist - für meinen Anwendungsfall - zu ungenau. Eine Maschine muss gesteuert werden.

    Hallo goran,

    was ist das für eine Maschine? 😕

    .. nur mal angenommen, w hat die Einheit 1000km, dann ist das "ungenaue" Ergebnis -3.01755e-17km bzw. -3.01755e-14m bzw. -3.01755e-2pm (pikometer). Der Durchmesser eines Wasserstoffatom liegt in der Größenordnung von 35pm.
    Ich stelle mir gerade einen Roboter vor, der einen 1,6km langen Arm hat (-0.00161579 * 1000km), der über eine Mechanismus in der Armschulter am Finger mit einer Genauigkeit von weniger als 1% eines Atomdurchmessers gesteuert werden soll. Und das ist Dir nicht genau genug 😉

    Dein Problem ist nicht die 'unzureichende Genauigkeit' eines double - Dein Problem liegt woanders!

    Gruß
    Werner



  • Übrigens, wenn du deine Konstanten nicht beschneidest, dann kommt du auch mit nur 80 Bit Genauigkeit schon ein Stück weiter:
    http://ideone.com/wWtDI

    Kommt allerdings u.a. auch auf den Compiler an, nicht überall hat long double größere Genauigkeit als double.



  • goran schrieb:

    Seien folgende Werte gegeben:
    
    w = -0.00161579
    rho = -3.23158e-05
    Igrad = 0.0004
    gamma = 0.02
    
    Weiter sei angenommen y = rho * gamma. Dann folgt:
    
    y = -3.23158e-05 * 0,02
      = -0,0000323158 * 0,02
      = -0
        -  0
        -   00000646216
        ---------------
        -0,000000646216
    
    Weiter sei angenommen z = y / Igrad. Dann folgt:
    
    z = -0,000000646216 / 0,0004
      = -0,000000646216 / (4/10000)
      = -0,000000646216 * (10000/4) 
      = -0,00646216 / 4
      = -0,00161554
    
    Weiter sei angenommen A = w - rho * gamma / Igrad. Dann folgt:
    
    A = w - rho * gamma / Igrad
      = w - y / Igrad
      = w - z
      = -0,00161579 - -0,00161554
      = -0,00161579 +  0,00161554
      = -0,00000025
    
    Damit folgt A != 0.
    

    Ferner gilt -0,00000025 < -2.16840434497101e-19 < -3.01755e-20.
    Dann gilt auch der das -2.16840434497101e-19 näher an der Wahrheit liegt wenn -0,00000025 die Wahrheit ist.

    Erstmal ist -3.23158e-05 * 0,02 = -0,000000646316 nicht -0,000000646216. Übertrag vergessen. Damit kommt tatsächlich 0 raus.
    Und damit ist auch -3.01755e-20 näher an der Wahrheit.


Anmelden zum Antworten