2014-09-12 13 views
8

ho qualche codice molto semplice:Come viene troppopieno virgola mobile maneggiati iostreams

#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; 
} 

Quando compilo questo codice con g ++ 4.1.2 ed eseguito su Redhat 5,10 (compilatore stesso), ottengo l'uscita :

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

Quando eseguo lo stesso binario su Linux Redhat 6.5 (compilatore 4.4.7), ottengo

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

Qual è la posta comportamento corretto? Underflow è succeeeding su 4.4.7 ma fallisce su 4.1.2. Overflow fallisce (ma cambia ancora il valore) su 4.4.7 e fallisce senza modificare nulla su 4.1.2.

Il comportamento non definito o semplicemente errato su uno o l'altro?

+0

Buona domanda. '>>' è indirettamente (tramite 'num_get') definito in termini di regole di' strtold', e per quest'ultimo, è esplicitamente non specificato se l'underflow è trattato come una condizione di errore. Tuttavia, l'underflow è * non * trattato come una delle condizioni di errore per 'num_get'. Non sono sicuro di cosa significhi che sia non specificato, o ben definito come restituire 0 con successo. – hvd

risposta

3

Secondo C++ 11 22.4.2.1.2, la conversione dovrebbe fallire per l'overflow, ma non per il underflow. In caso di overflow, dovrebbe comunque fornire un valore del massimo valore rappresentabile e impostare failbit.

Quindi il tuo compilatore più recente ha il comportamento moderno corretto.

Tuttavia, entrambi i tuoi vecchi compilatori sono precedenti a C++ 11 da molti anni. In standard precedenti, la conversione è stata specificata per fornire un errore se scanf; e non dare un valore in caso di errore. Passando allo standard C, scanf passa a strtod, che a sua volta specifica un errore in overflow; ma se c'è un errore in underflow è definito dall'implementazione.

Quindi il compilatore più vecchio è coerente con il comportamento storico.