double - double = nan ???



  • Hi,

    ich habe in meinem Programm folgende Zeilen:

    double* point = ug0->GetPointData()->GetVectors()->GetTuple3(i);
    
    // simpe calculation
    double temp = sqrt(point[0] * point[0]
                     + point[1] * point[1]
                     + point[2] * point[2]);
    
    // calculation with norm function
    double temp2 = vtkMath::Norm(point, 3);
    
    cout << "Difference: " << (temp2 - temp) << endl;
    

    Eigenltlich sollte die Differenz immer Null ergeben. Ich weiss, mit der Null ist das so ne Sache in der Informatik (Maschinengenauigkeit)...

    Folgende Ausgabe wird erzeugt:
    nan
    nan
    0
    nan
    nan
    nan
    nan
    0
    0
    0
    nan
    0
    0
    0

    Was bedeutet nan? "Not A Number" hab ich mehrfach im Internet gefunden. Was bedeutet das für mich? Ist temp = temp2, falls die Differenz beider nan ergibt?
    Kann man mit 'nan' rechnen wie mit '0'? Das dürfte ja nicht gehen, wenn es keinen Zahl ist.

    Gruss, K.B.



  • NaN entsteht, wenn eine Rechenoperation undefinierte Werte zurückliefert (z.B. die Wurzel aus einer negativen Zahl). Und wirklich damit rechnen kannst du leider nicht - wenn ein Operand NaN ist, kommt als Ergebnis wieder NaN heraus.

    Für weitere Informationen empfehle ich z.B. das Wikipedia: NaN



  • Mit welchen Zahlen hat man es zu tun?

    Mach mal ein vollständiges lauffähiges Programm, das den Fehler zeigt.


  • Mod

    unter drei bedingungen, die hier zu nan führen können:
    - point[0] * point[0] + point[1] * point[1] + point[2] * point[2] ist unendlich, dann ist auch die wurzel daraus unendlich, die differenz zweier unendlichkeiten ist allerdings nan
    - wenigstens eine der komponenten von point ist bereits ein nan
    - vtkMath::Norm produziert möglicherweise auch sonst nans - code fehlt

    denkbar wäre, dass du irgenwann versucht hast, einen 0-vektor zu normieren (division durch 0 führt zu unendlichkeiten in den komponenten und der erste fall tritt ein).



  • Gibt mal noch die Werte von 'temp' und 'temp2' aus, denn einer der Werte müßte dann ja NaN sein.



  • Hi,

    danke für die Infos. Tatsächlich steckt in einem der Point[i] bereits das nan oder ein inf.

    Ich habe die Spur zurückverfolgt und bin an nun an einer Stelle, die nan, inf und -inf liefern kann. Diese Funktion soll nicht abgeändert werden. Ich möchte nun aber die Fälle nan, inf und -inf abfangen und gesondert behandeln. Wie funktioniert das?

    double a = EineFunktion(...); // liefert meist ein gültigen Double-Wert, ab und an auch nan, inf oder -inf
    
    if (a == inf)
      ...
    

    Sowas geht leider nicht.
    Gibts eine andere Möglichkeit?

    Gruss, K.B.


  • Mod

    das läßt sich recht leicht durch ein paar einfache funktionen machen, etwa

    bool is_nan(double x) { return x != x; }
    bool is_pos_inf(double x)
    {
        static double null = 0;
        static const double inf = 1 / null;
        return x == inf;
    }
    bool is_neg_inf(double x)
    {
        static double null = 0;
        static const double inf = -1 / null;
        return x == inf;
    }
    


  • Das macht man besser mit Standardmitteln machen. Man will doch keine SIGFPE erhalten.

    if (d == std::numeric_limits<double>::infinity()) {
       std::cout << "d is infinity\n";
    }
    


  • Hi,

    die Abfrage mit std::numeric_limits<double>::infinity() funktioniert einwandfrei! Schonmal besten Danke für den Hinweis.

    Unter http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/structstd_1_1numeric__limits.html gibts auch entsprechende Funktionen quiet_NaN()und signaling_NaN(). Diese fangen ein NaN in meinem Fall nicht ab. Ich verstehe auch nicht so recht was quiet_NaN()und signaling_NaN() machen soll.
    Als nächstes habe ich (var == 0.0 / 0.0) probiert. Dies konnte die Variablen auch nicht finden.

    Mit (var != var) hat es schließlich geklappt. Aber ich verstehe nicht warum. Ist denn NaN und NaN nicht das gleiche?

    Gruss, K.B.



  • Karl Blau schrieb:

    Ist denn NaN und NaN nicht das gleiche?

    Nein - NaN hat die (un)schöne Eigenschaft, daß jeder Vergleich damit "false" ergibt (selbst wenn die Werte identisch sind). Deshalb wird "x==quiet_NaN();" auch niemals true zurückliefern.

    PS: alternativ zu der "x!=x" Variante könntest du die Werte auch binär miteinander vergleichen (per memcmp()).


Anmelden zum Antworten