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 ï¬oating 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