Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

#552 ObjectToDouble(nan) native API failure on AIX

v4.0
closed
Rick McGuire
APIs (66)
5
2012-08-14
2008-10-29
Mark Miesfeld
No

Hi Rick,

Think I need help with this one too. Rather than post to the list, I thought I'd open up a bug so you can look at it when you have time.

On AIX, in the CONVERSION.testGroup these types of test cases are failing:

val = "nan"
self~assertSame(val, .CONVERSIONTester~TestObjectToDouble(val))

Rather than nan, they are producing +infinity

[failure] [20081029 16:31:13.155443]
svn: r3371 Change date: 2008-09-21 06:33:29 +0200
Test: TESTDOUBLE03
Class: CONVERSION.testGroup
File: /daten/svn/ooRexx/test/trunk/ooRexx/API/oo/CONVERSION.testGroup
Line: 827
Failed: assertSame
Expected: [[nan], identityHash="100785925"]
Actual: [[-infinity], identityHash="112493565"]

I think it is a difference in the C++ libraries on AIX, maybe coming from here in StringClass.cpp:

// non numeric, so this could be one of the special cases
if (strCompare("nan"))
{
    result = std::numeric_limits<double>::signaling_NaN();
    return true;
}

But, I'm not sure. Plus, I don't really know what to do about it even if it is the root cause. <grin>

I'll attach the log output.

Discussion

  • Rick McGuire
    Rick McGuire
    2008-10-29

    I see two potential places where things can go wrong, but this most likely is due to a problem in the C++ libraries. The first place is where you noted. It's possible that std::numeric_limits<double>::signaling_NaN() is not actually returning a NaN value. The other place is in NumberString::newInstanceFromDouble() where the double object is converted back into a Rexx object. It is possible that the test for isnan() is failing, but given that an "==" comparison is always supposed to fail for a NaN value, the comparison to -HUGE_VAL should not work. The other possibility is it made it through all of the if special cases and sprintf() formatted the value as "-infinity" for us. Understanding where the "-infinity" string comes from would help narrow down the real point of failure.

     
  • Rainer Tammer
    Rainer Tammer
    2008-10-30

    Hello,
    in the test you use val = "nan".
    where is nan defined ??

    this is a little test:

    include <stdio.h>

    include <math.h>

    int main(void)
    {

    double number = NAN;  /* NAN comes from math.h */
    printf("number=%ld\n");
    

    ....
    // make a nan value a string value
    if (isnan(number))
    {
    printf(">0\n");
    }
    else if (number == +HUGE_VAL)
    {
    printf("+infinity\n");
    }
    else if (number == -HUGE_VAL)
    {
    printf("-infinity\n");
    }
    return(0);
    }

    ./test_isnan
    number=804399748

    0

    Bye
    Rainer

     
  • Rick McGuire
    Rick McGuire
    2008-10-30

    I'm not sure I understand what you mean by "where is nan defined ??". In that context, "nan" is just the character string "nan". The ObjectToDouble() code recognizes that value as special and returns the value "std::numeric_limits<double>::signaling_NaN()" as a result. This is part of the standard C++ standard library. That's the value you need to be using in your test program.

     
  • Rainer Tammer
    Rainer Tammer
    2008-10-30

    Hello,
    on Linux (SLES9 / 32 bit):

    ./test
    number=1074642088

    0

    Bye
    Rainer

     
  • Rainer Tammer
    Rainer Tammer
    2008-10-30

    Hello,
    I am not good the the C++ stuff ... but here is another example:

    include <stdio.h>

    include <math.h>

    include <limits>

    int main(void)
    {

    /* double number = NAN; */
    double number = std::numeric_limits<double>::signaling_NaN();
    printf("number=%lld\n", number);
    
    // make a nan value a string value
    if (isnan(number))
    {
        printf(">0\n");
    }
    else if (number == -HUGE_VAL)
    {
      printf("HUGE_VAL");
    }
    else
    {
        printf("no\n");
    }
    return(0);
    

    }

    ./test_isnan
    number=-4503599627370496
    HUGE_VAL

    Bye
    Rainer

     
  • Rainer Tammer
    Rainer Tammer
    2008-10-30

    Hello,
    ok here is the thing:

    With the following test:

    include <stdio.h>

    include <math.h>

    include <limits>

    int main(void)
    {

    /* double number = NAN; */
    double number = std::numeric_limits<double>::signaling_NaN();
    
    if (isnan(number))
    {
        printf(">0\n");
    }
    else if (number == +HUGE_VAL)
    {
      printf("+HUGE_VAL\n");
    }
    else if (number == -HUGE_VAL)
    {
      printf("-HUGE_VAL\n");
    }
    else
    {
        printf("none\n");
    }
    return(0);
    

    }

    I get the following results:

    Linux SLES9 / 32 Bit
    ./test

    0

    AIX 5.3 32 bit compile on 64 bit OS:

    ./test
    -HUGE_VAL

    Bye
    Rainer

     
  • Rick McGuire
    Rick McGuire
    2008-10-30

    Well, that certainly seems to point to a problem with the value returned by std::numeric_limits<double>::signaling_NaN(). It appears to be returning the -infinity value rather than the signaling_NaN() value. Ok, a couple of things to try. First, what is the value of std::numeric_limits<double>::has_signaling_NaN()?

    Secondly, try your test using std::numeric_limits<double>::signaling_NaN(). It this works, there is a workaround for this problem.

     
  • Rainer Tammer
    Rainer Tammer
    2008-10-30

    Hello,
    I just checked... it looks like the return is -INF.

    template<>
    class _CXX_IMPORT numeric_limits<double>
    : public _Num_float_base {
    public:
    ...
    static _Ty signaling_NaN() _THROW0()
    {return (_Snan._D); }

    from yvals.h
    #define _Snan _Snan_ieee

    AIX defines NAN in math.h as:
    static const unsigned int _SQNAN = 0x7fc00000;

    define NAN (((float )(&_SQNAN)))

    Secondly, try your test using
    std::numeric_limits<double>::signaling_NaN(). It this works, there is a
    workaround for this problem.

    ?? std::numeric_limits<double>::signaling_NaN() is what I have used in my example...

    Bye
    Rainer

     
  • Rainer Tammer
    Rainer Tammer
    2008-10-30

    Hello,
    if (std::numeric_limits<double>::has_signaling_NaN)
    printf("std::numeric_limits<double>::has_signaling_NaN() true\n");

    => true

     
  • Rick McGuire
    Rick McGuire
    2008-10-30

    Sorry, I meant std::numeric_limits<double>::quiet_NaN(). But also need to know the result returned by std::numeric_limits<double>::has_signaling_NaN() and std::numeric_limits<double>::has_quiet_NaN(). Trying to do too many things at once leads to copy and paste errors :-)

     
  • Rainer Tammer
    Rainer Tammer
    2008-10-30

    Hello,
    yes std::numeric_limits<double>::quiet_NaN() is there and it looks like isnan() returns >0..
    This is the class for double (from limits)

                // CLASS numeric_limits<double>
    

    template<>
    class _CXX_IMPORT numeric_limits<double>
    : public _Num_float_base {
    public:
    typedef double _Ty;
    static _Ty (min)() _THROW0()
    {return (DBL_MIN); }
    static _Ty (max)() _THROW0()
    {return (DBL_MAX); }
    static _Ty epsilon() _THROW0()
    {return (DBL_EPSILON); }
    static _Ty round_error() _THROW0()
    {return (0.5); }
    static _Ty denorm_min() _THROW0()
    {return (_Denorm._D); }
    static _Ty infinity() _THROW0()
    {return (_Inf._D); }
    static _Ty quiet_NaN() _THROW0()
    {return (_Nan._D); }
    static _Ty signaling_NaN() _THROW0()
    {return (_Snan._D); }
    _STCONS(int, digits, DBL_MANT_DIG);
    _STCONS(int, digits10, DBL_DIG);
    _STCONS(int, max_exponent, DBL_MAX_EXP);
    _STCONS(int, max_exponent10, DBL_MAX_10_EXP);
    _STCONS(int, min_exponent, DBL_MIN_EXP);
    _STCONS(int, min_exponent10, DBL_MIN_10_EXP);
    };

    I have changed one line in ooRexx (just as a test):

    interpreter/classes/StringClass.cpp

    • result = std::numeric_limits<double>::signaling_NaN();
    • result = std::numeric_limits<double>::quiet_NaN();

    With this change all tests from ooRexx/API/oo are sucessfully:

    ./runTest.sh -b -B -R ooRexx/API/oo
    Setting env for AIX
    Searching for test containers..
    Executing automated test suite..

    ooTest Framework - Automated Test of the ooRexx Interpreter

    Interpreter: REXX-ooRexx_4.0.0(MT) 6.03 30 Oct 2008
    ooRexxUnit: 2.0.0_3.2.0 ooTest: 1.0.0_4.0.0

    Tests ran: 474
    Assertions: 1494
    Failures: 0
    Errors: 0
    Skipped files: 0

    File search: 00:00:00.687537
    Suite construction: 00:00:00.157881
    Test execution: 00:00:00.490093
    Total time: 00:00:04.411396

    Bye
    Rainer

     
  • Rick McGuire
    Rick McGuire
    2008-10-30

    But you say that <double>has_signaling_NaN() is returning true? I really don't want to have this returning a quiet NaN on all platforms. This library seems like it's seriously messed up. A potential work around is to add the test "if (value == value)" (or even an isnan() test) to make sure we got a NaN value and fall back to the quiet NaN if necessary. I'd prefer that the sequence just use has_signaling_NaN(), but if that's not returning a valid result, we can't rely on that.

     
  • Rainer Tammer
    Rainer Tammer
    2008-10-30

    Hello,
    strange... it really looks like signaling_NaN() returns -INF on AIX.

    Here is another short test:

    include <iostream>

    include <limits>

    using namespace std;

    int main( )
    {
    cout << "The quiet NaN for type float is: "
    << numeric_limits<float>::quiet_NaN( )
    << endl;
    cout << "The quiet NaN for type double is: "
    << numeric_limits<double>::quiet_NaN( )
    << endl;
    cout << "The signaling NaN for type floatis: "
    << numeric_limits<float>::signaling_NaN( )
    << endl;
    cout << "The signaling NaN for type double is: "
    << numeric_limits<double>::signaling_NaN( )
    << endl;

    }

    The quiet NaN for type float is: -NaNQ
    The quiet NaN for type double is: -NaNQ
    The signaling NaN for type floatis: -INF
    The signaling NaN for type double is: -INF

    Bye
    Rainer

     
  • Mark Miesfeld
    Mark Miesfeld
    2008-10-30

    Rainer,

    Why don't you make your last program as the below, to be sure Rick can see what has_signaling_NaN is returning.

    include <iostream>

    include <limits>

    using namespace std;

    int main( )
    {
    cout << "(double) Has quiet nan: "
    << numeric_limits<double>::has_quiet_NaN
    << endl;
    cout << "(double) Has signaling nan: "
    << numeric_limits<double>::has_signaling_NaN
    << endl;

    cout << "(float) Has quiet nan:  "
         << numeric_limits<float>::has_quiet_NaN
         << endl;
    cout << "(float) Has signaling nan:  "
         << numeric_limits<float>::has_signaling_NaN
         << endl;
    

    cout << "The quiet NaN for type float is: "
    << numeric_limits<float>::quiet_NaN( )
    << endl;
    cout << "The quiet NaN for type double is: "
    << numeric_limits<double>::quiet_NaN( )
    << endl;
    cout << "The signaling NaN for type floatis: "
    << numeric_limits<float>::signaling_NaN( )
    << endl;
    cout << "The signaling NaN for type double is: "
    << numeric_limits<double>::signaling_NaN( )
    << endl;

    }

     
  • Rainer Tammer
    Rainer Tammer
    2008-10-30

    Hello,
    OK, this is the resilt for Marks sample:

    (double) Has quiet nan: 1
    (double) Has signaling nan: 1
    (float) Has quiet nan: 1
    (float) Has signaling nan: 1
    The quiet NaN for type float is: -NaNQ
    The quiet NaN for type double is: -NaNQ
    The signaling NaN for type floatis: -INF
    The signaling NaN for type double is: -INF

    currently I have added the following code to StringClass.cpp:

    // non numeric, so this could be one of the special cases
    if (strCompare("nan"))
    {
    

    ifdef AIX

        result = std::numeric_limits<double>::quiet_NaN();
    

    else

        result = std::numeric_limits<double>::signaling_NaN();
    

    endif

        return true;
    }
    

    Please could you give me a heads up what the problem is ??
    To be honest I do have a little problem with signaling and quiet...

    Bye
    Rainer

     
  • Rick McGuire
    Rick McGuire
    2008-10-30

    Sorry, there should be no platform-specific #ifdefs added to any of the shared code. It would be permissible to use something like #ifdef USE_QUIET_NAN and define that as part of the configuration, but no direct platform references should appear in common code.

    However, I'd prefer a method that didn't require any conditionals at all. For example, I think this would work:

       result = std::numeric_limits<double>::signaling_NaN();
       // this will be false if this is really a NaN value.  If true, 
       // then fall back and use the quiet version. 
       if (!isnan(result))
       {
           result = std::numeric_limits<double>::quiet_NaN();
       }
    
     
  • Rainer Tammer
    Rainer Tammer
    2008-10-30

    Hello,
    this was just as a quick test to see if the helps - not a suggestion for an patch.
    With this hack all unit test passes on AIX. I just have added your suggested code change. It should set the result reliable.

    Bye
    Rainer

     
  • Rainer Tammer
    Rainer Tammer
    2008-10-31

    Hello,
    it looks like not only AIX is acting differently...

    I have tested this on AIX, Linux and Windows (Windows has two different results depending on the C++ compiler used!!!)...

    On AIX and Linux NAN from math.h looks good.

    testnan.cpp

    include <iostream>

    include <limits>

    using namespace std;

    int main( )
    {
    cout << "(double) Has quiet nan: "
    << numeric_limits<double>::has_quiet_NaN
    << endl;
    cout << "(double) Has signaling nan: "
    << numeric_limits<double>::has_signaling_NaN
    << endl;

    cout << "(long double) Has quiet nan: "
    << numeric_limits<long double="">::has_quiet_NaN
    << endl;
    cout << "(long double) Has signaling nan: "
    << numeric_limits<long double="">::has_signaling_NaN
    << endl;

    cout << "(float) Has quiet nan: "
    << numeric_limits<float>::has_quiet_NaN
    << endl;
    cout << "(float) Has signaling nan: "
    << numeric_limits<float>::has_signaling_NaN
    << endl;

    cout << "The quiet NaN for type float is: "
    << numeric_limits<float>::quiet_NaN( )
    << endl;
    cout << "The quiet NaN for type double is: "
    << numeric_limits<double>::quiet_NaN( )
    << endl;
    cout << "The quiet NaN for type long double is: "
    << numeric_limits<long double="">::quiet_NaN( )
    << endl;

    cout << "The signaling NaN for type floatis: "
    << numeric_limits<float>::signaling_NaN( )
    << endl;
    cout << "The signaling NaN for type double is: "
    << numeric_limits<double>::signaling_NaN( )
    << endl;
    cout << "The signaling NaN for type long double is: "
    << numeric_limits<long double="">::signaling_NaN( )
    << endl;

    ifdef NAN

    cout << "NAN from math.h is: "
    << NAN
    << endl;

    endif

    }

    Linux

    ./testnan
    (double) Has quiet nan: 1
    (double) Has signaling nan: 1
    (long double) Has quiet nan: 1
    (long double) Has signaling nan: 1
    (float) Has quiet nan: 1
    (float) Has signaling nan: 1
    The quiet NaN for type float is: nan
    The quiet NaN for type double is: nan
    The quiet NaN for type long double is: nan
    The signaling NaN for type floatis: nan
    The signaling NaN for type double is: nan
    The signaling NaN for type long double is: nan
    NAN from math.h is: nan

    AIX

    ./testnan
    (double) Has quiet nan: 1
    (double) Has signaling nan: 1
    (long double) Has quiet nan: 1
    (long double) Has signaling nan: 1
    (float) Has quiet nan: 1
    (float) Has signaling nan: 1
    The quiet NaN for type float is: -NaNQ
    The quiet NaN for type double is: -NaNQ
    The quiet NaN for type long double is: -NaNQ
    The signaling NaN for type floatis: -INF
    The signaling NaN for type double is: -INF
    The signaling NaN for type long double is: -INF
    NAN from math.h is: NaNQ

    Windows MS VC V12 (Visual Studio 6)

    testnan.exe
    (double) Has quiet nan: 1
    (double) Has signaling nan: 1
    (long double) Has quiet nan: 1
    (long double) Has signaling nan: 1
    (float) Has quiet nan: 1
    (float) Has signaling nan: 1
    The quiet NaN for type float is: -1.#IND
    The quiet NaN for type double is: -1.#IND
    The quiet NaN for type long double is: -1.#IND
    The signaling NaN for type floatis: -1.#INF
    The signaling NaN for type double is: -1.#INF
    The signaling NaN for type long double is: -1.#INF

    Windows MS VC V13 (Visual C++ Toolkit 2003)

    testnan.exe
    (double) Has quiet nan: 1
    (double) Has signaling nan: 1
    (long double) Has quiet nan: 1
    (long double) Has signaling nan: 1
    (float) Has quiet nan: 1
    (float) Has signaling nan: 1
    The quiet NaN for type float is: 1.#QNAN
    The quiet NaN for type double is: 1.#QNAN
    The quiet NaN for type long double is: 1.#QNAN
    The signaling NaN for type floatis: 1.#QNAN
    The signaling NaN for type double is: 1.#QNAN
    The signaling NaN for type long double is: 1.#QNAN

    So this is quite messed up. What do you think Rick ?

    Bye
    Rainer

     
  • Rick McGuire
    Rick McGuire
    2008-10-31

    We don't support VC++ 6 any more, so I'm not terribly concerned about that one. It appears that my fix of using the signalling NaN and ensuring that isnan() is true will work. You might want to add an isnan() test for both the signalling NaN and the quiet NaN to your program though, since having isnan() work is key to getting the round-trip conversion working properly.

     
  • Rainer Tammer
    Rainer Tammer
    2008-10-31

    Hello,
    currently I use this version (which is working, all unit tests passes):

    // non numeric, so this could be one of the special cases
    if (strCompare("nan"))
    {
        result = std::numeric_limits<double>::signaling_NaN();
        // this will be false if this is really a NaN value. If true,
        // then fall back and use the quiet version.
        if (!isnan(result))
        {
          result = std::numeric_limits<double>::quiet_NaN();
        }
        return true;
    }
    

    so the bullet proof version would be:

    // non numeric, so this could be one of the special cases
    if (strCompare("nan"))
    {
        result = std::numeric_limits<double>::signaling_NaN();
        // this will be false if this is really a NaN value. If true,
        // then fall back and use the quiet version.
        if (!isnan(result))
        {
          result = std::numeric_limits<double>::quiet_NaN();
    

    ifdef HAVE_MATH_NAN / must come from configure... /

          if(!isnan(result))
          {
            result = NAN;
          }
          else
          {
              /* yield error ?? */
          }
    

    endif

        }
        return true;
    }
    

    I just checked that NAN from math.h also works - all unit tests passes.

    Bye
    Rainer

     


Anonymous


Cancel   Add attachments