Here's my test code:
errno = 0;
d = strtod("1.8011670033376514e-308", NULL);
With this code, I get d == 1.8011670033376514e-308
and errno == ERANGE
.
From strtod(3):
If the correct value would cause overflow, plus or minus
HUGE_VAL
(HUGE_VALF
,HUGE_VALL
) is returned (according to the sign of the value), andERANGE
is stored inerrno
. If the correct value would cause underflow, zero is returned andERANGE
is stored inerrno
.
So, it seems to me that either errno
should be zero (no error) or d
should be zero (underflow).
Is this a bug, or am I missing something? This happens for many different versions of eglibc and gcc.
In §7.22.1.3 The strtod()
, strtof()
and strtold()
functions, the C11 standard (ISO/IEC 9899:2011) says:
The functions return the converted value, if any. If no conversion could be performed, zero is returned. If the correct value overflows and default rounding is in effect (7.12.1), plus or minus
HUGE_VAL
,HUGE_VALF
, orHUGE_VALL
is returned (according to the return type and sign of the value), and the value of the macroERANGE
is stored inerrno
. If the result underflows (7.12.1), the functions return a value whose magnitude is no greater than the smallest normalized positive number in the return type; whethererrno
acquires the valueERANGE
is implementation-defined.
The standard also notes in §5.2.4.2.2 Characteristics of floating types that IEC 60559 (IEEE 754) floating point numbers have the limit:
DBL_MIN 2.2250738585072014E-308 // decimal constant
Since 1.8011670033376514e-308 is smaller than DBL_MIN
, you get a sub-normal number, and ERANGE
is quite appropriate (but optional).
On Mac OS X 10.9.4 with GCC 4.9.1, the following program:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *end;
errno = 0;
double d = strtod("1.8011670033376514e-308", &end);
if (errno != 0)
{
int errnum = errno;
printf("%d: %s\n", errnum, strerror(errnum));
}
printf("%24.16e\n", d);
unsigned char *p = (unsigned char *)&d;
const char *pad = "";
for (size_t i = 0; i < sizeof(double); i++)
{
printf("%s0x%.2X", pad, *p++);
pad = " ";
}
putchar('\n');
return 0;
}
produces the output:
34: Result too large
1.8011670033376514e-308
0x01 0x00 0x00 0x00 0xA8 0xF3 0x0C 0x00
The error message is ironically wrong — the value is too small — but you can't have everything.
The code is behaving according to The Open Group's POSIX specification of strtod()
:
If the correct value would cause an underflow, a value whose magnitude is no greater than the smallest normalized positive number in the return type shall be returned and errno set to [ERANGE].
I'd say what you're seeing is an error in detail in the Linux manpage.
If strtod()
returned a non-zero value (that is not +/- HUGE_VAL
), the call has succeeded (according to the man page you quoted).
Referring to the man page for errno.h
:
The
<errno.h>
header file defines the integer variableerrno
, which is set by system calls and some library functions in the event of an error to indicate what went wrong. Its value is significant only when the return value of the call indicated an error (i.e.,-1
from most system calls;-1
orNULL
from most library functions); a function that succeeds is allowed to changeerrno
.
Thus, you can only check errno
for an error if the return value of your function actually returns a value indicating an error has occurred.
A more complete explanation of errno
(and an explanation of its relationship to strtod()
) can be found on another StackExchange.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With