Ist wirklich der round-off Error so gross????



  • Hallo Peter

    danke für den Tipp. Ich werde ihn probieren. Aber was mich wundert ist die Grosse des Werts e-019. Wenn er z.B. e-100 waere konnte ich gut damit leben.
    Laut Compaq Visaul Fortran Double nimmt 8 bytes von memory.

    danke noch mal



  • dann wundert es mich eigentlich, dass beim fortran double was anderes als hier rauskommt.
    warum solle der exponent so hoch sein? wenn die groesste belegte stelle im einer oder zehntel bereich ist, hat er doch gar keine chance, so kleine fehler zu machen.
    edit: vielleicht kann ja der fortran compiler die ausdruecke entsprechend optimieren, vergleich doch mal den asm output.

    [ Dieser Beitrag wurde am 18.06.2003 um 20:13 Uhr von PeterTheMaster editiert. ]



  • wenn in Fortran 0.0 rauskommt, kann das nicht vielleicht unter Umständen daran liegen, dass die Ausgabefunktion bereits rundet? Bei Excel kann ich mir das auf jeden Fall vorstellen.



  • Also am wichtigesten ist so wenig rechnen wie möglich. also aus

    0.5 * gravty * 1./3. * ...

    ein 1./6. * gravty * ... machen, etc.

    Dann gibts noch verschiedene Arten, wie der Prozessor rundet (zumindest bei Intel-kompatiblen). Das kan man IMHO nur per ASM umstellen. Vielleicht ist das, was der MSVC verwendet, schlecht geeignet für deine rechnungen.



  • was ist an blah*10^-19 so gross?



  • ich weiss nicht ob das was hilft:
    wenn ich die Variablen als long double deklariere dann erhalte ich haargenau 0.0000(..

    float vergrössert den fehler auf 1.7e-10



  • OOOOOPS....

    ich bin vorher einem Fehler aufgesessen. (Die printf funktion verlangt %lf für long double)

    Der Fehler bei long double beträgt noch 2.1684e-19



  • Liebe Freunde,

    danke für die Tipps. Was mich noch stört ist das so.
    Ich reduziere die oprationen in folgendweise (die Konstante werde nich mehr in den Oprationen eingeschrieben!!!) Damit erhoe ich die Grosse der Werte, trotzdem ist der Fehler noch da. Der Wert von sum sollte eigentlich gleich wie Endergebniss von ResVx sein!!!

    double gravty = 1.0;
    double x1,x2,x3;
    double y1,y2,y3;
    double z1,z2,z3;

    double h1,h2,h3;

    double wse, dt, A, slopX;
    double bedSlope1, bedSlope2, bedSlope3;
    double pressurX1, pressurX2, pressurX3;
    double ResVx = 0.0;

    void main()
    {
    x1 = 6.25e+1, x2 = 6.25e+1, x3 = 6.49999976e+1;
    y1 = 1.40000001e+1, y2 = 1.20000005e+1, y3 = 1.20000005e+1;
    z1 = 0.0, z2 = 0.0, z3 = 0.5; // z3 = 5.0e-1

    wse = 0.55;
    cout << " Enter the Water Surface Elevation? wse > 0.55";
    cin >> wse;
    dt = 1.0;

    h1 = wse - z1;
    h2 = wse - z2;
    h3 = wse - z3;

    A = 0.5 * ((x2*y3-x3*y2)+(x3*y1-x1*y3)+(x1*y2-x2*y1));
    slopX = (z1*(y2-y3)+z2*(y3-y1)+z3*(y1-y2));

    double tmp = 1./3.;
    bedSlope1 = h1;
    bedSlope2 = h2;
    bedSlope3 = h3;

    pressurX1 = (h1 * h1 + h2 * h2 + h1 *h2) *(y1 - y2);
    pressurX2 = (h2 * h2 + h3 * h3 + h2 *h3) *(y3 - y2);
    pressurX3 = (h3 * h3 + h1 * h1 + h3 *h1) *(y1 - y3);

    printf(" x1 = %19.15f , x2 = %19.15f , x3 = %19.15f \n", x1,x2,x3);
    printf(" y1 = %19.15f , y2 = %19.15f , y3 = %19.15f \n", y1,y2,y3);
    printf(" z1 = %19.15f , z2 = %19.15f , z3 = %19.15f \n", z1,z2,z3);
    printf(" h1 = %19.15f , h2 = %19.15f , h3 = %19.15f \n", h1,h2,h3);
    printf(" A = %19.15f , slopX = %19.15f \n", A,slopX);
    printf(" bedSlope1 = %19.15f , bedSlope2 = %19.15f , bedSlope3 = %19.15f \n", bedSlope1, bedSlope2, bedSlope3);
    printf(" pressurX1 = %19.15f , pressurX2 = %19.15f , pressurX3 = %19.15f \n", pressurX1, pressurX2, pressurX3);

    double in1 = (-slopX * (h1+h2+h3));

    double in2 = (+pressurX1 - pressurX2 - pressurX3);
    // in2 = -(y3*(z2-z1)+y2*(z1-z3)+y1*(z3-z2))(z1+z2+z3-3wse);
    double sum = (in1 + in2);

    printf(" sum = %19.15e \n", sum);

    ResVx -= dt * slopX * bedSlope1;
    ResVx += dt * pressurX1;
    printf(" ResVx = %19.15e \n", ResVx);

    ResVx -= dt * slopX * bedSlope2;
    ResVx -= dt * pressurX2;
    printf(" ResVx = %19.15e \n", ResVx);

    ResVx -= dt * slopX * bedSlope3;
    ResVx -= dt * pressurX3;
    printf(" ResVx = %19.15e \n", ResVx);
    }



  • 1.) Benutze doch bitte CodeTags
    2.) Du solltest dir angewöhnen globale Variablen zu vermeiden indem du lokale benutzt und diese bei Erstellung auch initialisierst. Du programmierst C++ und nicht irgendein uralt-C oder FORTRAN. siehe hier

    [ Dieser Beitrag wurde am 19.06.2003 um 18:10 Uhr von MaSTaH editiert. ]



  • Du sagtest, du hättest VC++. Ich weiß jetzt natürlich nicht welche Version (6 oder 7 (7 == .NET)).

    Also bei Version 7 (.NET) klickst du mit Rechts auf dein Projekt und sagst "Eigenschaften". Da dann unter "C/C++"->Optimierung->Gleitkommakonsistenz kann man auswählen "Konsistenz verbessern". Ich habe keine Ahnung was das genau bewirkt, weil ich es bisher nicht benutzt habe, aber vielleicht hilft dir das ja.

    Ansonsten sollte man ein paar Regeln bei diesen Berechnungen beachten:
    -niemals mit zu kleinen Zahlen rechnen, weil die Genauigkeit beschränkt ist
    -niemals mit zu großen Werten rechnen, weil dann ebenfalls die Genauigkeit flöten geht
    -niemals ganz oft Werte addieren, wenn es eine Multiplikation auch täte (weil Zahlen nur ungenau repräsentiert werden können und sich der Fehler bei der Addition dann kumuliert, er bei EINER Multiplikation aber nur gering ausfällt)

    Daher sollte man immer erst multiplizieren bevor man dividiert. Aber mit ewig großen Zahlen sollte man auch nicht rechnen.
    Aber wahrscheinlich weißt du das ja schon alles.

    Ach ja, bei Visual C++ 6.0 müsste es auch eine Einstellung geben, die die Genauigkeit erhöht (bzw. die sich so anhört als täte sie das 😉

    Jan.


Anmelden zum Antworten