/******************************************************************************* * * Copyright (C) 1998-2001, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* * File ieeetest.cpp * * Modification History: * * Date Name Description * 08/21/98 stephen Creation. ******************************************************************************* */ #include #include // DBL_MAX #include "ieeetest.h" #include "unicode/utypes.h" #include "unicode/putil.h" //============================== int main(int argc, char **argv) { int flags = IEEETest::kNone; // parse command line switches for(int i = 1; i < argc; ++i) { if(argv[i][0] == '-') { switch(argv[i][1]) { case 'v': flags += IEEETest::kVerboseMode; break; case '?': case 'h': case 'H': usage(argv[0]); return 0; default: break; } } } IEEETest test(flags); return test.run(); } //============================== void usage(const char *execName) { fprintf(stdout, "usage: %s [flags]\n\n" "Flags:\n" "-v Verbose mode\n", execName); } //============================== IEEETest::IEEETest(int flags) : mFlags(flags), mTestLevel(0), mNeedLogIndent(TRUE), mNeedErrIndent(TRUE) {} //============================== IEEETest::~IEEETest() {} //============================== int IEEETest::run(void) { int errCount = 0; logln(); log("Starting IEEETest").logln(); increaseTestLevel(); // add more tests here errCount += runTest("NaN behavior", &IEEETest::testNaN); errCount += runTest("+Infinity behavior", &IEEETest::testPositiveInfinity); errCount += runTest("-Infinity behavior", &IEEETest::testNegativeInfinity); errCount += runTest("Zero behavior", &IEEETest::testZero); decreaseTestLevel(); if(errCount == 0) log("IEEETest Passed"); else { log("IEEETest failed with ").log(errCount) .log(errCount == 1 ? " error." : " errors."); } logln(); if(errCount == 0 && ! (mFlags & kVerboseMode)) fprintf(stdout, "\nAll tests passed without error.\n"); return errCount; } //============================== int IEEETest::runTest(const char *testName, int (IEEETest::*testFunc)(void)) { logln().log("Running test ").log(testName).logln(); increaseTestLevel(); int errCount = (this->*testFunc)(); decreaseTestLevel(); log("Test ").log(testName); if(errCount == 0) log(" passed."); else { log(" failed with ").log(errCount) .log(errCount == 1 ? " error." : " errors."); } logln().logln(); return errCount; } //============================== // NaN is weird- comparisons with NaN _always_ return false, with the // exception of !=, which _always_ returns true int IEEETest::testNaN(void) { int errCount = 0; log("NaN tests may show that the expected NaN!=NaN etc. is not true on some").logln(); log("platforms; however, ICU does not rely on them because it defines").logln(); log("and uses uprv_isNaN(). Therefore, most failing NaN tests only report warnings.").logln(); errCount += runTest("isNaN", &IEEETest::testIsNaN); errCount += runTest("NaN >", &IEEETest::NaNGT); errCount += runTest("NaN <", &IEEETest::NaNLT); errCount += runTest("NaN >=", &IEEETest::NaNGTE); errCount += runTest("NaN <=", &IEEETest::NaNLTE); errCount += runTest("NaN ==", &IEEETest::NaNE); errCount += runTest("NaN !=", &IEEETest::NaNNE); log("End of NaN tests.").logln(); return errCount; } //============================== int IEEETest::testPositiveInfinity(void) { int errCount = 0; double pinf = uprv_getInfinity(); double ninf = -uprv_getInfinity(); double ten = 10.0; if(uprv_isInfinite(pinf) != TRUE) { err("FAIL: isInfinite(+Infinity) returned FALSE, should be TRUE.").errln(); errCount++; } if(uprv_isPositiveInfinity(pinf) != TRUE) { err("FAIL: isPositiveInfinity(+Infinity) returned FALSE, should be TRUE.").errln(); errCount++; } if(uprv_isNegativeInfinity(pinf) != FALSE) { err("FAIL: isNegativeInfinity(+Infinity) returned TRUE, should be FALSE.").errln(); errCount++; } if(pinf > DBL_MAX != TRUE) { err("FAIL: +Infinity > DBL_MAX returned FALSE, should be TRUE.").errln(); errCount++; } if(pinf > DBL_MIN != TRUE) { err("FAIL: +Infinity > DBL_MIN returned FALSE, should be TRUE.").errln(); errCount++; } if(pinf > ninf != TRUE) { err("FAIL: +Infinity > -Infinity returned FALSE, should be TRUE.").errln(); errCount++; } if(pinf > ten != TRUE) { err("FAIL: +Infinity > 10.0 returned FALSE, should be TRUE.").errln(); errCount++; } return errCount; } //============================== int IEEETest::testNegativeInfinity(void) { int errCount = 0; double pinf = uprv_getInfinity(); double ninf = -uprv_getInfinity(); double ten = 10.0; if(uprv_isInfinite(ninf) != TRUE) { err("FAIL: isInfinite(-Infinity) returned FALSE, should be TRUE.").errln(); errCount++; } if(uprv_isNegativeInfinity(ninf) != TRUE) { err("FAIL: isNegativeInfinity(-Infinity) returned FALSE, should be TRUE.").errln(); errCount++; } if(uprv_isPositiveInfinity(ninf) != FALSE) { err("FAIL: isPositiveInfinity(-Infinity) returned TRUE, should be FALSE.").errln(); errCount++; } if(ninf < DBL_MAX != TRUE) { err("FAIL: -Infinity < DBL_MAX returned FALSE, should be TRUE.").errln(); errCount++; } if(ninf < DBL_MIN != TRUE) { err("FAIL: -Infinity < DBL_MIN returned FALSE, should be TRUE.").errln(); errCount++; } if(ninf < pinf != TRUE) { err("FAIL: -Infinity < +Infinity returned FALSE, should be TRUE.").errln(); errCount++; } if(ninf < ten != TRUE) { err("FAIL: -Infinity < 10.0 returned FALSE, should be TRUE.").errln(); errCount++; } return errCount; } //============================== // notes about zero: // -0.0 == 0.0 == TRUE // -0.0 < 0.0 == FALSE // generating -0.0 must be done at runtime. compiler apparently ignores sign? int IEEETest::testZero(void) { int errCount = 0; // volatile is used to fake out the compiler optimizer. We really want to divide by 0. volatile double pzero = 0.0; volatile double nzero = 0.0; nzero *= -1; if(pzero == nzero != TRUE) { err("FAIL: 0.0 == -0.0 returned FALSE, should be TRUE.").errln(); errCount++; } if(pzero > nzero != FALSE) { err("FAIL: 0.0 > -0.0 returned TRUE, should be FALSE.").errln(); errCount++; } if(pzero >= nzero != TRUE) { err("FAIL: 0.0 >= -0.0 returned FALSE, should be TRUE.").errln(); errCount++; } if(pzero < nzero != FALSE) { err("FAIL: 0.0 < -0.0 returned TRUE, should be FALSE.").errln(); errCount++; } if(pzero <= nzero != TRUE) { err("FAIL: 0.0 <= -0.0 returned FALSE, should be TRUE.").errln(); errCount++; } if(uprv_isInfinite(1/pzero) != TRUE) { err("FAIL: isInfinite(1/0.0) returned FALSE, should be TRUE.").errln(); errCount++; } if(uprv_isInfinite(1/nzero) != TRUE) { err("FAIL: isInfinite(1/-0.0) returned FALSE, should be TRUE.").errln(); errCount++; } if(uprv_isPositiveInfinity(1/pzero) != TRUE) { err("FAIL: isPositiveInfinity(1/0.0) returned FALSE, should be TRUE.").errln(); errCount++; } if(uprv_isNegativeInfinity(1/nzero) != TRUE) { err("FAIL: isNegativeInfinity(1/-0.0) returned FALSE, should be TRUE.").errln(); errCount++; } return errCount; } //============================== int IEEETest::testIsNaN(void) { int numErrors = 0; double pinf = uprv_getInfinity(); double ninf = -uprv_getInfinity(); double nan = uprv_getNaN(); double ten = 10.0; if(uprv_isNaN(nan) == FALSE) { err("FAIL: isNaN() returned FALSE for NaN.").errln(); numErrors++; } if(uprv_isNaN(pinf) == TRUE) { err("FAIL: isNaN() returned TRUE for +Infinity.").errln(); numErrors++; } if(uprv_isNaN(ninf) == TRUE) { err("FAIL: isNaN() returned TRUE for -Infinity.").errln(); numErrors++; } if(uprv_isNaN(ten) == TRUE) { err("FAIL: isNaN() returned TRUE for 10.0.").errln(); numErrors++; } return numErrors; } //============================== int IEEETest::NaNGT(void) { double pinf = uprv_getInfinity(); double ninf = -uprv_getInfinity(); double nan = uprv_getNaN(); double ten = 10.0; int numErrors = 0; if(nan > nan != FALSE) { log("WARNING: NaN > NaN returned TRUE, should be FALSE").logln(); } if(nan > pinf != FALSE) { log("WARNING: NaN > +Infinity returned TRUE, should be FALSE").logln(); } if(nan > ninf != FALSE) { log("WARNING: NaN > -Infinity returned TRUE, should be FALSE").logln(); } if(nan > ten != FALSE) { log("WARNING: NaN > 10.0 returned TRUE, should be FALSE").logln(); } return numErrors; } //============================== int IEEETest::NaNLT(void) { double pinf = uprv_getInfinity(); double ninf = -uprv_getInfinity(); double nan = uprv_getNaN(); double ten = 10.0; int numErrors = 0; if(nan < nan != FALSE) { log("WARNING: NaN < NaN returned TRUE, should be FALSE").logln(); } if(nan < pinf != FALSE) { log("WARNING: NaN < +Infinity returned TRUE, should be FALSE").logln(); } if(nan < ninf != FALSE) { log("WARNING: NaN < -Infinity returned TRUE, should be FALSE").logln(); } if(nan < ten != FALSE) { log("WARNING: NaN < 10.0 returned TRUE, should be FALSE").logln(); } return numErrors; } //============================== int IEEETest::NaNGTE(void) { double pinf = uprv_getInfinity(); double ninf = -uprv_getInfinity(); double nan = uprv_getNaN(); double ten = 10.0; int numErrors = 0; if(nan >= nan != FALSE) { log("WARNING: NaN >= NaN returned TRUE, should be FALSE").logln(); } if(nan >= pinf != FALSE) { log("WARNING: NaN >= +Infinity returned TRUE, should be FALSE").logln(); } if(nan >= ninf != FALSE) { log("WARNING: NaN >= -Infinity returned TRUE, should be FALSE").logln(); } if(nan >= ten != FALSE) { log("WARNING: NaN >= 10.0 returned TRUE, should be FALSE").logln(); } return numErrors; } //============================== int IEEETest::NaNLTE(void) { double pinf = uprv_getInfinity(); double ninf = -uprv_getInfinity(); double nan = uprv_getNaN(); double ten = 10.0; int numErrors = 0; if(nan <= nan != FALSE) { log("WARNING: NaN <= NaN returned TRUE, should be FALSE").logln(); } if(nan <= pinf != FALSE) { log("WARNING: NaN <= +Infinity returned TRUE, should be FALSE").logln(); } if(nan <= ninf != FALSE) { log("WARNING: NaN <= -Infinity returned TRUE, should be FALSE").logln(); } if(nan <= ten != FALSE) { log("WARNING: NaN <= 10.0 returned TRUE, should be FALSE").logln(); } return numErrors; } //============================== int IEEETest::NaNE(void) { double pinf = uprv_getInfinity(); double ninf = -uprv_getInfinity(); double nan = uprv_getNaN(); double ten = 10.0; int numErrors = 0; if(nan == nan != FALSE) { log("WARNING: NaN == NaN returned TRUE, should be FALSE").logln(); } if(nan == pinf != FALSE) { log("WARNING: NaN == +Infinity returned TRUE, should be FALSE").logln(); } if(nan == ninf != FALSE) { log("WARNING: NaN == -Infinity returned TRUE, should be FALSE").logln(); } if(nan == ten != FALSE) { log("WARNING: NaN == 10.0 returned TRUE, should be FALSE").logln(); } return numErrors; } //============================== int IEEETest::NaNNE(void) { double pinf = uprv_getInfinity(); double ninf = -uprv_getInfinity(); double nan = uprv_getNaN(); double ten = 10.0; int numErrors = 0; if(nan != nan != TRUE) { log("WARNING: NaN != NaN returned FALSE, should be TRUE").logln(); } if(nan != pinf != TRUE) { log("WARNING: NaN != +Infinity returned FALSE, should be TRUE").logln(); } if(nan != ninf != TRUE) { log("WARNING: NaN != -Infinity returned FALSE, should be TRUE").logln(); } if(nan != ten != TRUE) { log("WARNING: NaN != 10.0 returned FALSE, should be TRUE").logln(); } return numErrors; } //============================== IEEETest& IEEETest::log(char c) { if(mFlags & kVerboseMode) { if(mNeedLogIndent) { for(int j = 0; j < 2 * getTestLevel(); ++j) fputc(' ', stdout); mNeedLogIndent = FALSE; } fputc(c, stdout); } return *this; } //============================== IEEETest& IEEETest::log(const char *s) { if(mFlags & kVerboseMode) { if(mNeedLogIndent) { for(int j = 0; j < 2 * getTestLevel(); ++j) fputc(' ', stdout); mNeedLogIndent = FALSE; } fprintf(stdout, "%s", s); } return *this; } //============================== IEEETest& IEEETest::log(int i) { if(mFlags & kVerboseMode) { if(mNeedLogIndent) { for(int j = 0; j < 2 * getTestLevel(); ++j) fputc(' ', stdout); mNeedLogIndent = FALSE; } fprintf(stdout, "%d", i); } return *this; } //============================== IEEETest& IEEETest::log(long l) { if(mFlags & kVerboseMode) { if(mNeedLogIndent) { for(int j = 0; j < 2 * getTestLevel(); ++j) fputc(' ', stdout); mNeedLogIndent = FALSE; } fprintf(stdout, "%ld", l); } return *this; } //============================== IEEETest& IEEETest::log(double d) { if(mFlags & kVerboseMode) { if(mNeedLogIndent) { for(int j = 0; j < 2 * getTestLevel(); ++j) fputc(' ', stdout); mNeedLogIndent = FALSE; } fprintf(stdout, "%g", d); } return *this; } //============================== IEEETest& IEEETest::logln(void) { if(mFlags & kVerboseMode) fputc('\n', stdout); mNeedLogIndent = TRUE; return *this; } //============================== IEEETest& IEEETest::err(char c) { if(mNeedErrIndent) { for(int j = 0; j < 2 * getTestLevel(); ++j) fputc(' ', stderr); mNeedErrIndent = FALSE; } fputc(c, stderr); return *this; } //============================== IEEETest& IEEETest::err(const char *s) { if(mNeedErrIndent) { for(int j = 0; j < 2 * getTestLevel(); ++j) fputc(' ', stderr); mNeedErrIndent = FALSE; } fprintf(stderr, "%s", s); return *this; } //============================== IEEETest& IEEETest::err(int i) { if(mNeedErrIndent) { for(int j = 0; j < 2 * getTestLevel(); ++j) fputc(' ', stderr); mNeedErrIndent = FALSE; } fprintf(stderr, "%d", i); return *this; } //============================== IEEETest& IEEETest::err(long l) { if(mNeedErrIndent) { for(int j = 0; j < 2 * getTestLevel(); ++j) fputc(' ', stderr); mNeedErrIndent = FALSE; } fprintf(stderr, "%ld", l); return *this; } //============================== IEEETest& IEEETest::err(double d) { if(mNeedErrIndent) { for(int j = 0; j < 2 * getTestLevel(); ++j) fputc(' ', stderr); mNeedErrIndent = FALSE; } fprintf(stderr, "%g", d); return *this; } //============================== IEEETest& IEEETest::errln(void) { fputc('\n', stderr); mNeedErrIndent = TRUE; return *this; } //eof