Opened 9 years ago

Closed 9 years ago

#6138 closed defect (fixed)

Incorrect negative NAN behavior in cpl_strtod.cpp:CPLStrtodDelim

Reported by: Kurt Schwehr Owned by: warmerdam
Priority: normal Milestone:
Component: default Version: svn-trunk
Severity: normal Keywords:
Cc:

Description

-1.#QNAN ends up giving back a NAN rather than -NAN. That seems to be wrong.

source:trunk/gdal/port/cpl_strtod.cpp#L265

It could just do:

#include <limits>

// snip
return -std::numeric_limits<double>::quiet_NaN();

What are the implications of changing this?

    if (nptr[0] == '-')
    {
        if (strcmp(nptr, "-1.#QNAN") == 0 ||
            strcmp(nptr, "-1.#IND") == 0)
        {
            if( endptr ) *endptr = (char*)nptr + strlen(nptr);
            return NAN;
        }

to

    if (nptr[0] == '-')
    {
        if (strcmp(nptr, "-1.#QNAN") == 0 ||
            strcmp(nptr, "-1.#IND") == 0)
        {
            if( endptr ) *endptr = (char*)nptr + strlen(nptr);
            return -std::numeric_limits<double>::quiet_NaN();
        }

Change History (6)

comment:1 by Kurt Schwehr, 9 years ago

Here is the proposed patch. Will this work with MSVC compilers, Android etc?

  • cpl_strtod.cpp

    svn diff
     
    2929 ****************************************************************************/
    3030
    3131#include <locale.h>
    32 #include <errno.h>
    33 #include <stdlib.h>
    3432
     33#include <cerrno>
     34#include <cstdlib>
     35#include <limits>
     36
    3537#include "cpl_conv.h"
    3638
    3739CPL_CVSID("$Id$");
     
    4446}
    4547#endif
    4648
    47 #ifndef NAN
    48 #  ifdef HUGE_VAL
    49 #    define NAN (HUGE_VAL * 0.0)
    50 #  else
    51 
    52 static float CPLNaN(void)
    53 {
    54     float fNan;
    55     int nNan = 0x7FC00000;
    56     memcpy(&fNan, &nNan, 4);
    57     return fNan;
    58 }
    59 
    60 #    define NAN CPLNan()
    61 #  endif
    62 #endif
    63 
    64 #ifndef INFINITY
    65     static CPL_INLINE double CPLInfinity(void)
    66     {
    67         static double ZERO = 0;
    68         return 1.0 / ZERO; /* MSVC doesn't like 1.0 / 0.0 */
    69     }
    70     #define INFINITY CPLInfinity()
    71     static CPL_INLINE double CPLNegInfinity(void)
    72     {
    73         static double ZERO = 0;
    74         return -1.0 / ZERO; /* MSVC doesn't like -1.0 / 0.0 */
    75     }
    76     #define NEG_INFINITY CPLNegInfinity()
    77 #else
    78     #define NEG_INFINITY (-INFINITY)
    79 #endif
    80 
    8149/************************************************************************/
    8250/*                            CPLAtofDelim()                            */
    8351/************************************************************************/
     
    266234            strcmp(nptr, "-1.#IND") == 0)
    267235        {
    268236            if( endptr ) *endptr = (char*)nptr + strlen(nptr);
    269             return NAN;
     237            return -std::numeric_limits<double>::quiet_NaN();
    270238        }
    271239
    272240        if (strcmp(nptr,"-inf") == 0 ||
     
    273241            EQUALN (nptr,"-1.#INF",strlen("-1.#INF")))
    274242        {
    275243            if( endptr ) *endptr = (char*)nptr + strlen(nptr);
    276             return NEG_INFINITY;
     244            return -std::numeric_limits<double>::infinity();
    277245        }
    278246    }
    279247    else if (nptr[0] == '1')
     
    281249        if (strcmp(nptr, "1.#QNAN") == 0)
    282250        {
    283251            if( endptr ) *endptr = (char*)nptr + strlen(nptr);
    284             return NAN;
     252            return std::numeric_limits<double>::quiet_NaN();
    285253        }
    286254        if( EQUALN (nptr,"1.#INF",strlen("1.#INF")) )
    287255        {
    288256            if( endptr ) *endptr = (char*)nptr + strlen(nptr);
    289             return INFINITY;
     257            return std::numeric_limits<double>::infinity();
    290258        }
    291259    }
    292260    else if (nptr[0] == 'i' && strcmp(nptr,"inf") == 0)
    293261    {
    294262        if( endptr ) *endptr = (char*)nptr + strlen(nptr);
    295         return INFINITY;
     263        return std::numeric_limits<double>::infinity();
    296264    }
    297265    else if (nptr[0] == 'n' && strcmp(nptr,"nan") == 0)
    298266    {
    299267        if( endptr ) *endptr = (char*)nptr + strlen(nptr);
    300         return NAN;
     268        return std::numeric_limits<double>::quiet_NaN();
    301269    }
    302270
    303271/* -------------------------------------------------------------------- */

comment:2 by Kurt Schwehr, 9 years ago

Trying out limit and quiet_NaN via r30769

Note that I see comments to the effect of Tru64 support around the isnan. Do we need to support Tru64 for gdal >= 2.1.0 when support for the os was EOL'ed 3 years ago? If we support platforms with NaN and Inf issues, wht is the current list?

in reply to:  2 comment:3 by Even Rouault, 9 years ago

Note that I see comments to the effect of Tru64 support around the isnan. Do we need to support Tru64 for gdal >= 2.1.0 when support for the os was EOL'ed 3 years ago?

Probably not. I've hardly heard about that platform before

If we support platforms with NaN and Inf issues, wht is the current list?

No idea... GDAL at least compiles on most Debian architectures ( https://packages.debian.org/wheezy/gdal-bin ), not sure about the runtime correctness however. Plus some BSD's. Plus Android.

comment:4 by Kurt Schwehr, 9 years ago

Reapplied argdataset.cpp nan test as r30781. It appears to work in travis-ci runs.

comment:6 by Kurt Schwehr, 9 years ago

Resolution: fixed
Status: newclosed

Going to call this done. I think the current behavior is fine now that we have the std:: way of specifying NaNs and Inf.

Note: See TracTickets for help on using tickets.