2014-09-12 5 views
8

ich einige sehr einfachen Code haben:Wie wird Gleitkommaüberlauf in iostreams behandelt

#include <iostream> 
#include <sstream> 
using namespace std; 

int main() 
{ 
    stringstream is("1.0 2.0 1e-500 1e500 12.0"); 
    double d = {17.0, 17.0, 17.0, 17.0, 17.0}; 

    for (int i=0; i < 5; ++i) 
    { 
    if (is >> d[i]) 
    { 
     cout<<"Conversion succeeded"<<endl; 
    } 
    else 
    { 
     cout<<"Conversion failed"<<endl; 
     is.clear(); 
    } 
    } 
    for (int i=0; i < 5; ++i) cout<<d[i]<<endl; 
} 

Wenn ich diesen Code mit g ++ 4.1.2 kompilieren und auf Redhat 5,10 (gleiche Compiler) laufen lasse, erhalte ich die Ausgabe :

Conversion succeeded 
Conversion succeeded 
Conversion failed 
Conversion failed 
Conversion succeeded 
1 
2 
0 
17 
17 
12 

Wenn ich die gleiche binäre auf Redhat Linux 6.5 (Compiler 4.4.7) ausführen, bekomme ich

Conversion succeeded 
Conversion succeeded 
Conversion succeeded 
Conversion failed 
Conversion succeeded 
1 
2 
0 
1.79769e+308 
12 

Was die e erwartetes Verhalten? Unterlauf ist erfolgreich bei 4.4.7, aber nicht bei 4.1.2. Der Überlauf schlägt fehl (ändert aber immer noch den Wert) bei 4.4.7 und schlägt fehl, ohne etwas an 4.1.2 zu ändern.

Ist das Verhalten undefiniert oder einfach falsch auf dem einen oder anderen?

+0

Gute Frage. '>>' ist indirekt (über 'num_get') definiert durch die Regeln von' strtold', und für letzteres ist explizit nicht spezifiziert, ob Unterlauf als Fehlerbedingung behandelt wird. Der Unterlauf wird jedoch nicht als eine der Fehlerbedingungen für "num_get" behandelt. Ich bin mir nicht sicher, ob das bedeutet, dass es unspezifiziert oder wohldefiniert ist, 0 erfolgreich zurückzugeben. – hvd

Antwort

3

Gemäß C++ 11 22.4.2.1.2 sollte die Konvertierung für Überlauf, aber nicht für Unterlauf fehlschlagen. Im Falle eines Überlaufs sollte es immer noch einen Wert des größten darstellbaren Wertes geben und failbit setzen.

So hat Ihr neueren Compiler das richtige moderne Verhalten.

Allerdings sind beide Ihrer alten Compiler C++ 11 um viele Jahre älter. In früheren Standards wurde die Umwandlung spezifiziert, um einen Fehler zu geben, wenn scanf würde; und im Fehlerfall keinen Wert angeben. Wendet man sich dem C-Standard zu, verschiebt scanf zu strtod, der wiederum einen Fehler bei Überlauf angibt; Aber ob ein Fehler beim Unterlauf vorliegt, ist implementierungsdefiniert.

Ihr älterer Compiler ist also konsistent mit historischem Verhalten.

Verwandte Themen