strtod ("nan") returns negative NaN

Craig Howland howland@LGSInnovations.com
Tue Aug 14 17:49:00 GMT 2018


On 08/14/2018 11:05 AM, Masamichi Hosoda wrote:
> Hi
>
> I've found that strtod ("nan") returns negative NaN on Cygwin 64 bit.
> https://cygwin.com/ml/cygwin/2018-08/msg00168.html
>
> On Linux with glibc, both strtod ("nan")
> and strtod ("-nan") return positive NaN.
>
> So I've created the patch that behaves like glibc.
> Both strtod ("nan") and strtod ("-nan") return positive NaN.
>
> Sample code:
> ```
> #include <stdio.h>
> #include <stdlib.h>
>
> int main (void)
> {
>    printf ("strtof (\"nan\", NULL) = %f\n", strtof ("nan", NULL));
>    printf ("strtof (\"-nan\", NULL) = %f\n", strtof ("-nan", NULL));
>    printf ("strtod (\"nan\", NULL) = %f\n", strtod ("nan", NULL));
>    printf ("strtod (\"-nan\", NULL) = %f\n", strtod ("-nan", NULL));
>    printf ("strtold (\"nan\", NULL) = %Lf\n", strtold ("nan", NULL));
>    printf ("strtold (\"-nan\", NULL) = %Lf\n", strtold ("-nan", NULL));
> }
> ```
>
> The result of Cygwin (newlib) without my patch:
> ```
> strtof ("nan", NULL) = nan
> strtof ("-nan", NULL) = nan
> strtod ("nan", NULL) = -nan
> strtod ("-nan", NULL) = nan
> strtold ("nan", NULL) = -nan
> strtold ("-nan", NULL) = -nan
> ```
> ...
>
> Thanks.
The Newlib math functions generally do support signed NANs.  The C standard says 
(in section 5.2.4.2.2 Characteristics of floating types <float.h>) NANs can be 
treated as having a sign or not.  But since the math library does support signed 
NANs, the proper behavior for the strtox() functions would be to listen to the 
sign rather than ignoring it.  So while the current Cygwin 64 behavior is 
clearly incorrect, the given patch needs to be adjusted to listen to sign.

(It can be seen that the math functions support signed NANs by looking, for 
example, at s_copysign.c.  it blindly copies the sign without checking the type 
of the arguments.  The standard requires requests to set sign to be ignored when 
NANs are not treated as having signs.)

I cannot generate git diffs at this time (corporate firewall), but here is how I 
think strtof() would need to be fixed after strtod() is:

$ diff -pu strtod.c.20180420 strtod.c
--- strtod.c.20180420    2018-04-20 10:32:36.974479745 -0400
+++ strtod.c    2018-08-14 13:27:57.958177691 -0400
@@ -1285,7 +1285,7 @@ strtof_l (const char *__restrict s00, ch
  {
    double val = _strtod_l (_REENT, s00, se, loc);
    if (isnan (val))
-    return nanf (NULL);
+    return copysign( nanf (NULL), signbit(val) ? -1.0f : 1.0f);
    float retval = (float) val;
  #ifndef NO_ERRNO
    if (isinf (retval) && !isinf (val))
@@ -1300,7 +1300,7 @@ strtof (const char *__restrict s00,
  {
    double val = _strtod_l (_REENT, s00, se, __get_current_locale ());
    if (isnan (val))
-    return nanf (NULL);
+    return copysign( nanf (NULL), signbit(val) ? -1.0f : 1.0f);
    float retval = (float) val;
  #ifndef NO_ERRNO
    if (isinf (retval) && !isinf (val))


By the way, here are the results of the test prints from an embedded 64-bit ARM:

strtof ("nan", NULL) = 0.000000
strtof ("-nan", NULL) = 0.000000
strtod ("nan", NULL) = nan
strtod ("-nan", NULL) = nan
strtold ("nan", NULL) = inf
strtold ("-nan", NULL) = 2315841784746322880031071374419981810209660594968745666
57923565917084799991808.000000

Craig



More information about the Newlib mailing list