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.
Mark Miesfeld
2008-10-29
Failing test cases on AIX
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
2008-10-30
Hello,
in the test you use val = "nan".
where is nan defined ??
this is a little test:
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
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
2008-10-30
Hello,
on Linux (SLES9 / 32 bit):
./test
number=1074642088
0
Bye
Rainer
Rainer Tammer
2008-10-30
Hello,
I am not good the the C++ stuff ... but here is another example:
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
2008-10-30
Hello,
ok here is the thing:
With the following test:
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
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
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;
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
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
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
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
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
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
2008-10-30
Hello,
strange... it really looks like signaling_NaN() returns -INF on AIX.
Here is another short test:
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
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.
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
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")) {
result = std::numeric_limits<double>::quiet_NaN();
result = std::numeric_limits<double>::signaling_NaN();
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
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
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
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.
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;
cout << "NAN from math.h is: "
<< NAN
<< endl;
}
./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
./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
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
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
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
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();
if(!isnan(result)) { result = NAN; } else { /* yield error ?? */ }
} return true; }
I just checked that NAN from math.h also works - all unit tests passes.
Bye
Rainer
Anonymous