strtod underflow, return value != 0 - c

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), and ERANGE is stored in errno. If the correct value would cause underflow, zero is returned and ERANGE is stored in errno.
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, or HUGE_VALL is returned (according to the
return type and sign of the value), and the value of the macro ERANGE is stored in
errno. 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; whether
errno acquires the value ERANGE 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 variable errno, 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 or NULL from most library functions); a
function that succeeds is allowed to change errno.
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.

Related

Why errno is not set to EDOM even sqrt takes out of domain arguement?

errno is not being set to EDOM for domain error of sqrt() function in windows
It shows correctly on Linux but failed on windows (Using GCC 7.4) ...
#include <stdio.h>
#include <errno.h>
#include <math.h>
int main () {
double val;
errno = 0;
val = sqrt(-10);
if(errno == EDOM) {
printf("Invalid value \n");
} else {
printf("Valid value\n");
}
errno = 0;
val = sqrt(10);
if(errno == EDOM) {
printf("Invalid value\n");
} else {
printf("Valid value\n");
}
return(0);
}
Expected result : Invalid value
Valid value
Actual result : Valid value
Valid value
The math functions are not required to set errno. They might, but they don't have to. See section 7.12.1 of the C standard. Theoretically you can inspect the value of the global constant math_errhandling to find out whether they will, but that's not fully reliable on any implementation I know of, and may not even be defined (it's a macro, so you can at least use #ifdef to check for it).
Instead, you can check whether the input is negative before calling sqrt, or (if your implementation properly supports IEEE 754 in detail) you can check whether the output is NaN (using isnan) afterward.
As #zwol observed, the Standard allows implementations some latitude with respect to how (and whether) the math functions signal errors. In particular:
On a domain error, the function returns an implementation-defined
value; if the integer expression math_errhandling & MATH_ERRNO is
nonzero, the integer expression errno acquires the value EDOM; if the
integer expression math_errhandling & MATH_ERREXCEPT is nonzero, the
''invalid'' floating-point exception is raised.
(C11, paragraph 7.12.1/2)
Upon a domain error in sqrt,
On Linux with glibc, NaN is returned, errno is set to EDOM, and a floating-point exception is raised.
On Windows with recent MS runtime library, an indefinite NaN is returned, and a floating-point exception is raised, maybe (the docs are a bit unclear to me, but definitely some kind of status flag is set that you can subsequently evaluate via the _matherr() function). There is no mention of setting errno.

How can I parse an integer but keep "0" as a valid value using strtol?

This might seem super obvious but strtol provides a response to the parsed integer -- but it's 0 on fail. What if the integer I parsed is 0?
errno is only guaranteed to be set in the case of over/underflow (to ERANGE). For other errors you must check the value of endptr. Quoting C89:
long int strtol(const char *nptr, char **endptr, int base);
If the subject sequence is empty or does not have the expected
form, no conversion is performed; the value of nptr is stored in the
object pointed to by endptr, provided that endptr is not a null
pointer.
Normally endptr is set to point to the next character in the input string after the last character converted, so if it's the equal to the beginning of the string, you can be sure no conversion has been performed. For example,
char *nptr = "not a number", *endptr;
long n = strtol(nptr, &endptr, 10);
assert(nptr != endptr); //false
POSIX contains a handy extension which also sets errno to EINVAL in this case, but this is nonstandard.
According to man strtol:
If no conversion could be performed, 0 is returned and the global variable errno is set to
EINVAL (the last feature is not portable across all platforms).
Is that not the case on you platform? If so, what platform are you on?
You can check for the presence of errno as indicated in the example here on CppReference.

Does strtol("-2147483648", 0, 0) overflow if LONG_MAX is 2147483647?

Per the specification of strtol:
If the subject sequence has the expected form and the value of base is 0, the sequence of characters starting with the first digit shall be interpreted as an integer constant. If the subject sequence has the expected form and the value of base is between 2 and 36, it shall be used as the base for conversion, ascribing to each letter its value as given above. If the subject sequence begins with a minus-sign, the value resulting from the conversion shall be negated. A pointer to the final string shall be stored in the object pointed to by endptr, provided that endptr is not a null pointer.
The issue at hand is that, prior to the negation, the value is not in the range of long. For example, in C89 (where the integer constant can't take on type long long), writing -2147483648 is possibly an overflow; you have to write (-2147483647-1) or similar.
Since the wording using "integer constant" could be interpreted to apply the C rules for the type of an integer constant, this might be enough to save us from undefined behavior here, but the same issue (without such an easy out) would apply to strtoll.
Finally, note that even if it did overflow, the "right" value should be returned. So this question is really just about whether errno may or must be set in this case.
Although I cannot point to a particular bit of wording in the standard today, when I wrote strtol for 4BSD back in the 1990s I was pretty sure that this should not set errno, and made sure that I would not. Whether this was based on wording in the standard, or personal discussion with someone, I no longer recall.
In order to avoid overflow, this means the calculation has to be done pretty carefully. I did it in unsigned long and included this comment (still in the libc source in the various BSDs):
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set 'any' if any `digits' consumed; make it negative to indicate
* overflow.
*/
I was (and still am, to some extent) annoyed by the asymmetry between this action in the C library and the syntax of the language itself (where negative numbers are two separate tokens, - followed by the number, so that writing -217483648 means -(217483648) which becomes -(217483648U) which is of course 217483648U and hence positive! (Assuming 32-bit int of course; the problematic value varies for other bit sizes.)
Based on the comp.std.c thread cited in a comment by ouah (9 years ago), the intent is clearly that it does not overflow. The actual language in the standard is still ambiguous:
If the subject sequence has the expected form and the value of base is zero, the sequence of characters starting with the first digit is interpreted as an integer constant according to the rules of 6.4.4.1. If the subject sequence has the expected form and the value of base is between 2 and 36, it is used as the base for conversion, ascribing to each letter its value as given above. If the subject sequence begins with a minus sign, the value resulting from the conversion is negated (in the return type).
In order to get the right behavior, you have to interpret the phrase "interpreted as an integer constant according to the rules of 6.4.4.1" as yielding an actual integer value, not a value within some C-language integer type, and the final "in the return type" as the negation happening with a typeless integer value as the operand, but a coerced type for the result.
Moreover, the error condition does not actually even define an "overflow" condition, but "correct value outside the range". This part of the text seems to be ignoring the unsigned issue addressed in DR006, since it only deals with the final value, not the pre-negation value:
If the correct value is outside the range of representable values, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the return type and sign of the value, if any), and the value of the macro ERANGE is stored in errno.
In short, this seems to still be a mess, due to the usual outcome where the committee says "yeah, it's supposed to mean what you think it should mean" and then never updates the ambiguous or outright wrong text in the standard...
On a 32-bit platform, -2147483648 is not an overflow under C89. It's LONG_MIN for and errno == 0.
Quoting directly from the standard
RETURN VALUE
Upon successful completion strtol() returns the converted value, if
any. If no conversion could be performed, 0 is returned and errno may
be set to [EINVAL]. If the correct value is outside the range of
representable values, LONG_MAX or LONG_MIN is returned (according to
the sign of the value), and errno is set to [ERANGE].
When tested, this seems to be in line with the following test:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
int main(int argc, char *argv[]) {
long val = strtol(argv[1], NULL, 10);
fprintf(stderr, "long max: %ld, long min: %ld\n", LONG_MAX, LONG_MIN);
fprintf(stderr, "val: %ld, errno: %d\n", val, errno);
perror(argv[1]);
return 0;
}
When compiled as this on a 32-bit x86 system using:
gcc -std=c89 foo.c -o foo
produces the following outputs:
./foo -2147483648
Output:
long max: 2147483647, long min: -2147483648
val: -2147483648, errno: 0
-2147483648: Success
./foo -2147483649
Output:
long max: 2147483647, long min: -2147483648
val: -2147483648, errno: 34
-2147483649: Numerical result out of range

strtol using errno

I have the following code:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
void main(void)
{
int data;
char * tmp;
data = strtol("23ef23",&tmp,10);
printf("%d",errno);
getchar();
}
output is 0 ...
why?
i am using visual studio 2010 C++
code must be C89 compatible.
strtol only sets errno for overflow conditions, not to indicate parsing failures. For that purpose, you have to check the value of the end pointer, but you need to store a pointer to the original string:
char const * const str = "blah";
char const * endptr;
int n = strtol(str, &endptr, 0);
if (endptr == str) { /* no conversion was performed */ }
else if (*endptr == '\0') { /* the entire string was converted */ }
else { /* the unconverted rest of the string starts at endptr */ }
I think the only required error values are for underflow and overflow.
Conversely, if the entire string has been consumed in the conversion, you have *endptr = '\0', which may be an additional thing you might want to check.
Your logic does not fit with the 'spec'.
see this
An invalid value does not necessarily set 'errno'.
(copy follows)
long int strtol ( const char * str, char ** endptr, int base );
Convert string to long integer
Parses the C string str interpreting its content as an integral number of the specified base, which is returned as a long int value.
The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes as many characters as possible that are valid following a syntax that depends on the base parameter, and interprets them as a numerical value. Finally, a pointer to the first character following the integer representation in str is stored in the object pointed by endptr.
If the value of base is zero, the syntax expected is similar to that of integer constants, which is formed by a succession of:
An optional plus or minus sign
An optional prefix indicating octal or hexadecimal base ("0" or "0x" respectively)
A sequence of decimal digits (if no base prefix was specified) or either octal orhexadecimal digits if a specific prefix is present
If the base value is between 2 and 36, the format expected for the integral number is a succession of the valid digits and/or letters needed to represent integers of the specified radix (starting from '0' and up to 'z'/'Z' for radix 36). The sequence may optionally be preceded by a plus or minus sign and, if base is 16, an optional "0x" or "0X" prefix.
If the first sequence of non-whitespace characters in str is not a valid integral number as defined above, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.
Parameters
str
C string containing the representation of an integral number.
endptr
Reference to an object of type char*, whose value is set by the function to the next character in str after the numerical value.
This parameter can also be a null pointer, in which case it is not used.
Return Value
On success, the function returns the converted integral number as a long int value.
If no valid conversion could be performed, a zero value is returned.
If the correct value is out of the range of representable values, LONG_MAX or
LONG_MIN is returned, and the global variable errno is set to ERANGE.
It has been 10 years since the question was first posted, but the problem does not age. The answers given are either out of date (yet true for their time) or a bit confusing because I had to search more.
I have seen this in a book and met this post while searching for its meaning, and while checking the page for strtol, I ended up in this page on cplusplus.com of errno macro.
Your question has 2 parts to answer here:
First lets make a note of these 2 things about errno:
1- errno can be anything during the execution of a program for no function resets it (unless your own function does so)
errno is set to zero at program startup ...
any function ... can modify its value ...
no ... function sets its value back to zero
2- one has to reset it before calling a function that may use it.
should be reset ... to zero before the call ... since ... previous ... function may have altered its value
your program is pretty small, so no function seems to be there to change it. The sole visitors of errno are main program to set it to zero, and strtol in case of any error.
Yet, your program shows errno is 0, and this is confusing because one expects 23ef23 would not be converted to a number since it includes letters in it. However, this expectation is wrong, and actually, you get a number from this string thus there is really no error here, so no change is made to errno. and this makes the second part of the answer.
you will find this definition in strtol page
... takes as many characters as possible that are valid following a
syntax that depends on the base parameter, and interprets them as a
numerical value ... a pointer to the first character following is
stored.
instead of a long explanation, this following print statement and its output will suffice to visualize that above definition:
printf("%d %d %s",data,errno,tmp);
23 0 ef23
if you set the base to 16, output would be 2354979 0 . And base 2 would give 0 0 23ef23, showing that strtol will not freak if it does not find a number. The only error it will give will be ERANGE for breaching limits:
If the value read is out of the range of representable values by a
long int, the function returns LONG_MAX or LONG_MIN (defined in
), and errno is set to ERANGE.
You have to set errno to 0 before you call strtol. Otherwise you overwrite whatever value strtol set errno to.
You have to check tmp is not the same as "blablabla" pointer.
If data == 0 and tmp == "blablabla", then the input data is in the incorrect format. errno needs not to be set by the implementation if the input data is not in the expected format.
On strtol, strtoll, strtoul, and strtoull functions C says:
(C99, 7.20.1.4p7) If the subject sequence is empty or does not have the expected form, no conversion is performed; the value of nptr is stored in the object pointed to by endptr, provided that endptr is not a null pointer.
(C99, 7.20.1.4p9) The strtol, strtoll, strtoul, and strtoull functions return the converted
value, if any. If no conversion could be performed, zero is returned.

Odd behavior when converting C strings to/from doubles

I'm having trouble understanding C's rules for what precision to assume when printing doubles, or when converting strings to doubles. The following program should illustrate my point:
#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;
}
The output I get when I compile and run this program (on a Core 2 Duo with gcc 4.5.2) is:
DBL_MIN = 2.225074e-308, x = 2.225074e-310
Error converting '1e-310': Numerical result out of range
y = 1.000000e-310
My questions are:
Why is x printed as a nonzero number? I know compilers sometimes promote doubles to higher precision types for the purposes of computation, but shouldn't printf treat x as a 64-bit double?
If the C library is secretly using extended precision floating point numbers, why does strtod set errno when trying to convert these small numbers? And why does it produce the correct result anyway?
Is this behavior just a bug, a result of my particular hardware and development environment? (Unfortunately I'm not able to test on other platforms at the moment.)
Thanks for any help you can give. I will try to clarify the issue as I get feedback.
Because of the existence of denormal numbers in the IEEE-754 standard. DBL_MIN is the smallest normalised value.
Because the standard says so (C99 7.20.1.3):
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; whether errno acquires
the value ERANGE is implementation-defined.
Returning the "correct" value (i.e. 1e-310) obeys the above constraint.
So not a bug. This is technically platform-dependent, because the C standard(s) place no requirements on the existence or behaviour of denormal numbers (AFAIK).
Here is what the standard says for strtod underflow (C99, 7.20.1.3p10)
"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; whether errno acquires the value ERANGE is implementation-defined."
Regarding ERANGE on strtod underflow, here is what glibc says
"When underflow occurs, the underflow exception is raised, and zero (appropriately signed) is returned. errno may be set to ERANGE, but this is not guaranteed."
http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Math-Error-Reporting.html
(Note that this page is explicitly linked on glibc strtod page "Parsing of Floats":
http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Parsing-of-Floats.html

Resources