2012-01-09 20 views
7

Ho difficoltà a comprendere le regole di C per quale precisione assumere quando si stampa il doppio o quando si converte le stringhe in doppie. Il seguente programma dovrebbe illustrare il mio punto:Comportamento anomalo durante la conversione delle stringhe C in/da i doppi

#include <errno.h> 
#include <float.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(int argc, char **argv) { 
    double x, y; 
    const char *s = "1e-310"; 

    /* Should print zero */ 
    x = DBL_MIN/100.; 
    printf("DBL_MIN = %e, x = %e\n", DBL_MIN, x); 

    /* Trying to read in floating point number smaller than DBL_MIN gives an error */ 
    y = strtod(s, NULL); 
    if(errno != 0) 
     printf(" Error converting '%s': %s\n", s, strerror(errno)); 
    printf("y = %e\n", y); 

    return 0; 
} 

L'uscita ottengo quando compilare ed eseguire questo programma (su un Core 2 Duo con gcc 4.5.2) è:

DBL_MIN = 2.225074e-308, x = 2.225074e-310 
    Error converting '1e-310': Numerical result out of range 
y = 1.000000e-310 

Le mie domande sono :

  1. Perché x è stampato come numero diverso da zero? So che i compilatori a volte promuovono i duplicati a tipi di precisione più elevati ai fini del calcolo, ma non dovrebbero stampare x trattare x come un doppio a 64 bit?
  2. Se la libreria C utilizza segretamente numeri a virgola mobile di precisione estesa, perché strtod ha impostato errno durante il tentativo di convertire questi numeri piccoli? E perché produce comunque il risultato corretto?
  3. Questo comportamento è solo un bug, un risultato del mio particolare hardware e ambiente di sviluppo? (Purtroppo non sono in grado di testare su altre piattaforme al momento.)

Grazie per l'aiuto che puoi dare. Cercherò di chiarire il problema mentre ricevo feedback.

+0

Per uno:' DBL_MIN = 2.225074e-308' non ha molto senso dato che il valore IEEE DP minimo è '4.94066e-324' .Questo spiega perché la divisione per' 100' funziona ancora correttamente, ma la domanda è perché 'DBL_MIN' non è' 4.94066e-324'. – Mysticial

+0

Chiarito sotto: DBL_MIN è il il valore _normalised_ più piccolo –

risposta

8
  1. A causa dell'esistenza di denormal numbers nello standard IEEE-754. DBL_MIN è il più piccolo valore normalizzato.

  2. perché lo standard dice così (C99 7.20.1.3):

    If le underflow risultato (7.12.1), le funzioni restituiscono un valore la cui grandezza è non superiore del più piccolo normalizzata positiva numero nel tipo di reso; se errno acquisisce il valore ERANGE è definito dall'implementazione.

    La restituzione del valore "corretto" (vale a dire 1e-310) obbedisce al vincolo precedente.

  3. Quindi non un bug. Questo dipende tecnicamente dalla piattaforma, poiché lo standard C non pone requisiti sull'esistenza o sul comportamento dei numeri denormal (AFAIK).

+1

Grazie, questa è un'informazione molto utile. Desidero che strtod non segnali un errore in questo caso, ma posso vedere la logica. Lo farò semplicemente. –

7

Ecco ciò che la norma dice per strtod underflow (C99, 7.20.1.3p10)

"Se i underflow risultato (7.12.1), le funzioni restituiscono un valore la cui grandezza è non superiore a il più piccolo numero positivo normalizzato nel tipo di ritorno, se errno acquisisce il valore ERANGE è definito dall'implementazione. "

Per quanto riguarda ERANGE su strtod underflow, Ecco cosa dice

"Quando si verifica underflow, l'eccezione underflow viene sollevata, e lo zero (opportunamente firmato) viene restituito. Errno può essere impostato su ERANGE glibc, ma questo non è garantita."

http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Math-Error-Reporting.html

(Si noti che questa pagina è esplicitamente legato sulla glibc strtod pagina "Analisi dei Carri": http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Parsing-of-Floats.html

Problemi correlati