2012-01-09 20 views
7

Mam problem ze zrozumieniem zasad C dla jakiej precyzji zakładać przy drukowaniu podwajań lub przy zamianie ciągów na podwójne. Poniższy program powinien zilustrować mój punkt widzenia:Dziwne zachowanie podczas konwersji łańcuchów C do/z podwójnych

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

Wyjście mam kiedy skompilować i uruchomić ten program (na Core 2 Duo z gcc 4.5.2) jest:

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

Moje pytania są :

  1. Dlaczego x jest drukowany jako liczba niezerowa? Wiem, że kompilatory czasami promują podwojenia do wyższych typów precyzji do celów obliczeniowych, ale czy nie powinno się traktować x jako 64-bitowego podwójnego?
  2. Jeśli biblioteka C potajemnie używa liczb zmiennoprzecinkowych o rozszerzonej precyzji, dlaczego strtod ustawił wartość errno podczas próby konwersji tych małych liczb? I dlaczego tak czy inaczej daje prawidłowy wynik?
  3. Czy to zachowanie jest tylko błędem, wynikiem mojego szczególnego środowiska sprzętowego i programistycznego? (Niestety, nie mogę obecnie przetestować na innych platformach).

Dziękuję za pomoc, którą możesz udzielić. Postaram się wyjaśnić tę kwestię, gdy otrzymam informację zwrotną.

+0

Dla jednego:' DBL_MIN = 2.225074e-308' nie ma sensu ponieważ minimalna wartość IEEE DP wynosi "4.94066e-324" .To wyjaśnia, dlaczego dzielenie przez '100' nadal działa poprawnie.Ale pytanie brzmi, dlaczego' DBL_MIN' nie jest '4.94066e-324' . – Mysticial

+0

Wyjaśnienie poniżej: DBL_MIN jest najmniejszy _normalizowany_ wartość –

Odpowiedz

8
  1. Z powodu istnienia denormal numbers w standardzie IEEE-754. DBL_MIN jest najmniejszą wartością znormalizowaną .

  2. Ponieważ średnia tak mówi (C99 7.20.1.3)

    If się cieków wynik (7.12.1), funkcje zwrócić wartość którego wartość jest nie większa niż najmniejsza znormalizowane dodatni liczba w typie zwracanym; czy errno nabywa wartość ERANGE jest zdefiniowana przez implementację.

    Zwrócenie "prawidłowej" wartości (tj. 1e-310) jest zgodne z powyższym ograniczeniem.

  3. Więc nie błąd. Jest to technicznie zależne od platformy, ponieważ standard (y) C nie nakłada żadnych wymagań na istnienie lub zachowanie liczb denormalnych (AFAIK).

+1

Dziękuję, to jest bardzo pomocna informacja. Żałuję, że strtod nie zgłosiłby błędu w tym przypadku, ale widzę racjonalne uzasadnienie. Po prostu obejdę to. –

7

Oto co mówi średnia dla strtod dolnego (C99, 7.20.1.3p10)

„Jeśli cieków wynik (7.12.1), funkcje zwracają wartość, której wielkość nie jest większa niż najmniejsza znormalizowana liczba dodatnia w typie zwracanym, czy errno nabywa wartość ERANGE jest definiowana przez implementację. "

chodzi ERANGE na strtod dolnego, o to co glibc mówi

„Gdy występuje niedomiar, Odpływ jest wyjątek, a zero (odpowiednio podpisane) jest zwracana. Errno może być ustawione na ERANGE, ale to nie jest gwarantowane."

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

(Zauważ, że ta strona jest wyraźnie powiązany na glibc strtod stronie "parsowanie Pływaki": http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Parsing-of-Floats.html