Paul Eggert wrote: > > I propose to change the gradual underflow behaviour of xstrtod > > Sounds good. The current behavior with MSVC does make more sense.
Done: 2024-07-24 Bruno Haible <br...@clisp.org> xstrtod, xstrtold: Don't treat gradual underflow as an error. * lib/xstrtod.c (XSTRTOD): Upon gradual underflow, return true with errno = 0. * lib/xstrtod.h (xstrtod, xstrtold): Update specification. * tests/test-xstrtod.c (main): For gradual underflow, expect ok && errno == 0. * tests/test-xstrtold.c (main): Likewise. diff --git a/lib/xstrtod.c b/lib/xstrtod.c index a9ca7e8d10..7565658e4d 100644 --- a/lib/xstrtod.c +++ b/lib/xstrtod.c @@ -57,11 +57,18 @@ XSTRTOD (char const *str, char const **ptr, DOUBLE *result, else { /* Flag overflow as an error. - Flag gradual underflow as an error. + Flag gradual underflow as no error. Flag flush-to-zero underflow as no error. In either case, the caller can inspect *RESULT to get more details. */ if (val != 0 && errno == ERANGE) - ok = false; + { + if (val >= 1 || val <= -1) + /* Overflow. */ + ok = false; + else + /* Gradual underflow. */ + errno = 0; + } } if (ptr != NULL) diff --git a/lib/xstrtod.h b/lib/xstrtod.h index 8ceca6c433..f6a1ed888a 100644 --- a/lib/xstrtod.h +++ b/lib/xstrtod.h @@ -42,8 +42,7 @@ extern "C" { NaN true NaN 0 ±Infinity true ±HUGE_VAL 0 overflow false ±HUGE_VAL ERANGE - gradual underflow [!MSVC] false near zero ERANGE - gradual underflow [MSVC] true near zero 0 + gradual underflow true near zero 0 flush-to-zero underflow true ±0.0 ERANGE other finite value true value 0 @@ -68,8 +67,7 @@ bool xstrtod (const char *str, const char **ptr, double *result, NaN true NaN 0 ±Infinity true ±HUGE_VALL 0 overflow false ±HUGE_VALL ERANGE - gradual underflow [!MSVC] false near zero ERANGE - gradual underflow [MSVC] true near zero 0 + gradual underflow true near zero 0 flush-to-zero underflow true ±0.0L ERANGE other finite value true value 0 diff --git a/tests/test-xstrtod.c b/tests/test-xstrtod.c index 3464120f1e..e02d97203a 100644 --- a/tests/test-xstrtod.c +++ b/tests/test-xstrtod.c @@ -658,36 +658,20 @@ main () const char *ptr; double result = UNINIT; bool ok = xstrtod (input, &ptr, &result, strtod); -#if defined _MSC_VER ASSERT (ok); -#else - ASSERT (!ok); -#endif ASSERT (0.0 < result && result <= DBL_MIN); ASSERT (ptr == input + 6); -#if defined _MSC_VER ASSERT (errno == 0); -#else - ASSERT (errno == ERANGE); -#endif } { const char input[] = "-1e-320"; const char *ptr; double result = UNINIT; bool ok = xstrtod (input, &ptr, &result, strtod); -#if defined _MSC_VER ASSERT (ok); -#else - ASSERT (!ok); -#endif ASSERT (-DBL_MIN <= result && result < 0.0); ASSERT (ptr == input + 7); -#if defined _MSC_VER ASSERT (errno == 0); -#else - ASSERT (errno == ERANGE); -#endif } /* Flush-to-zero underflow. */ diff --git a/tests/test-xstrtold.c b/tests/test-xstrtold.c index b83e78067b..a8788ca100 100644 --- a/tests/test-xstrtold.c +++ b/tests/test-xstrtold.c @@ -662,18 +662,10 @@ main () const char *ptr; long double result = UNINIT; bool ok = xstrtold (input, &ptr, &result, strtold); -#if defined _MSC_VER ASSERT (ok); -#else - ASSERT (!ok); -#endif ASSERT (0.0L < result && result <= LDBL_MIN); ASSERT (ptr == input + strlen (input)); -#if defined _MSC_VER ASSERT (errno == 0); -#else - ASSERT (errno == ERANGE); -#endif } { #if LDBL_MAX_EXP > 10000 @@ -684,18 +676,10 @@ main () const char *ptr; long double result = UNINIT; bool ok = xstrtold (input, &ptr, &result, strtold); -#if defined _MSC_VER ASSERT (ok); -#else - ASSERT (!ok); -#endif ASSERT (-LDBL_MIN <= result && result < 0.0L); ASSERT (ptr == input + strlen (input)); -#if defined _MSC_VER ASSERT (errno == 0); -#else - ASSERT (errno == ERANGE); -#endif } /* Flush-to-zero underflow. */