Fließkomma - Wie hole ich mehr Genauigkeit heraus?



  • bestatigt: exakt null kommt raus, wie seppj bereits angemerkt hat.



  • w = w - rho * gamma / Igrad;

    für solche vorschulenaufgaben muss man also heutzutage matlab bemühen, interessant ... rofl, scnr.
    🙂



  • Könnte gut sein, das die verschiedenen compiler es in unterschiedlicher Reihenfolge rechnen, und man deshalb andere Ergebnisse bekommt. Kann da jemand den asm output vergleichen? Bin mit Assembler leider nicht so bewandert.



  • 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