2012-01-09 8 views
7

Tengo problemas para entender las reglas de C con respecto a la precisión que se debe asumir al imprimir dobles o al convertir cadenas a dobles. El siguiente programa debe ilustrar mi punto:Comportamiento extraño al convertir cadenas de C a dobles desde

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

La salida que consigo cuando compilar y ejecutar este programa (en un Core 2 Duo con gcc 4.5.2) es:

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

Mis preguntas son :

  1. ¿Por qué x se imprime como un número distinto de cero? Sé que los compiladores a veces promueven los dobles a tipos de precisión más altos para fines de computación, pero no deberían imprimir tratar x como un doble de 64 bits.
  2. Si la biblioteca C secretamente usa números de punto flotante de precisión extendida, ¿por qué strtod establece errno cuando intenta convertir estos números pequeños? ¿Y por qué produce el resultado correcto de todos modos?
  3. ¿Es este comportamiento solo un error, resultado de mi hardware particular y mi entorno de desarrollo? (Lamentablemente no puedo probar en otras plataformas en este momento).

Gracias por cualquier ayuda que pueda dar. Trataré de aclarar el problema a medida que recibo retroalimentación.

+0

Por un lado:' DBL_MIN = 2.225074e-308' no tiene mucho sentido ya que el valor mínimo de IEEE DP es '4.94066e-324'. Esto explica por qué dividir por' 100' todavía funciona correctamente. Pero la pregunta es por qué 'DBL_MIN' no es' 4.94066e-324'. – Mysticial

+0

Aclarado a continuación: DBL_MIN es el valor _normalised_ más pequeño –

Respuesta

8
  1. Debido a la existencia de denormal numbers en el estándar IEEE-754. DBL_MIN es el valor normalizado más pequeño valor.

  2. Debido a que la norma así lo indique (C99 7.20.1.3):

    If los underflow resultado (7.12.1), las funciones devuelven un valor cuya magnitud no es mayor que el más pequeño normalizado positivo número en el tipo de devolución; si errno adquiere , el valor ERANGE está definido por la implementación.

    Al devolver el valor "correcto" (es decir, 1e-310) se cumple la restricción anterior.

  3. Así que no es un error. Esto es técnicamente dependiente de la plataforma, porque los estándares C no imponen requisitos sobre la existencia o el comportamiento de los números denormales (AFAIK).

+1

Gracias, esta es una información muy útil. En cierto modo, me gustaría que strtod no señalara un error en este caso, pero puedo ver el razonamiento. Solo lo solucionaré. –

7

Esto es lo que dice la norma para strtod flujo inferior (C99, 7.20.1.3p10)

"Si los underflow resultado (7.12.1), las funciones devuelven un valor cuya magnitud no es mayor que el número positivo normalizado más pequeño en el tipo de retorno; si errno adquiere el valor ERANGE está definido por la implementación ".

En cuanto ERANGE en strtod flujo inferior, esto es lo que dice glibc

"Cuando se produce desbordamiento, se planteó la excepción de subdesbordamiento, y cero (firmado apropiadamente) se devuelve. Errno se puede establecer en ERANGE, pero esto no es garantizado"

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

(Tenga en cuenta que esta página se vincula explícitamente en glibc strtod página "de análisis de la flota": http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Parsing-of-Floats.html