/*********************************************************************** C program to test the setting of floating-point exception flags on Sun Solaris. Although all IEEE 754 implementations have these flags, the interface to them is unique to each vendor. Eventually, a common interface needs to be written to allow exception-flag access everywhere. [26-Jul-2001] ***********************************************************************/ #if defined(HAVE_LONG_DOUBLE) typedef long double LONG_DOUBLE; #else typedef double LONG_DOUBLE; #endif #include #include #include "args.h" #if defined(__sun) || defined(sun) #include #else /* This program is not expected to work correctly anywhere except on Sun Solaris, but provide sufficient definitions to at least allow it to compile, link, and run without error anywhere else. */ #define FP_X_INV 0x10 /* invalid operation exception */ #define FP_X_OFL 0x08 /* overflow exception */ #define FP_X_UFL 0x04 /* underflow exception */ #define FP_X_DZ 0x02 /* divide-by-zero exception */ #define FP_X_IMP 0x01 /* imprecise (loss of precision) */ typedef int fp_except; extern fp_except fpgetmask ARGS((void)); /* current exception mask */ extern fp_except fpsetmask ARGS((fp_except)); /* set mask, return previous */ extern fp_except fpgetsticky ARGS((void)); /* return logged exceptions */ extern fp_except fpsetsticky ARGS((fp_except)); /* change logged exceptions */ fp_except fpgetmask(VOID_ARG) { return ((fp_except)0); } #if STDC fp_except fpsetmask(fp_except e) #else fp_except fpsetmask(e) fp_except e; #endif { return ((fp_except)0); } fp_except fpgetsticky (VOID_ARG) { return ((fp_except)0); } #if STDC fp_except fpsetsticky(fp_except e) #else fp_except fpsetsticky(e) fp_except e; #endif { return ((fp_except)0); } #endif int main ARGS((void)); void clear ARGS((void)); void check ARGS((void)); double dpow ARGS((double d, int p)); float fpow ARGS((float f, int p)); LONG_DOUBLE qpow ARGS((LONG_DOUBLE q, int p)); void report ARGS((const char *s)); void separator ARGS((void)); int main(VOID_ARG) { float f; double d; LONG_DOUBLE q; separator(); report("\nTest at normal underflow limit\n"); clear(); report("\nfloat: 2^(-126)\n"); f = fpow((float)2.0, -126); check(); (void)fprintf(stderr, "f = %g\n", (double)f); clear(); report("\ndouble: 2^(-1022)\n"); d = dpow((double)2.0, -1022); check(); (void)fprintf(stderr, "d = %g\n", d); clear(); report("\nLONG_DOUBLE: 2^(-16382)\n"); q = qpow((LONG_DOUBLE)2.0, -16382); check(); (void)fprintf(stderr, "q = %Lg\n", q); separator(); report("\nTest of divide-by-two at normal underflow limit\n"); clear(); report("\nfloat: 2^(-127)\n"); f /= (float)2.0; check(); (void)fprintf(stderr, "f = %g\n", (double)f); clear(); report("\ndouble: 2^(-1023)\n"); d /= (double)2.0; check(); (void)fprintf(stderr, "d = %g\n", d); clear(); report("\nLONG_DOUBLE: 2^(-16383)\n"); q /= (LONG_DOUBLE)2.0; check(); (void)fprintf(stderr, "q = %Lg\n", q); separator(); report("\nTest of divide-by-two at normal underflow limit\n"); clear(); report("\nfloat: 2^(-128)\n"); f /= (float)2.0; check(); (void)fprintf(stderr, "f = %g\n", (double)f); clear(); report("\ndouble: 2^(-1024)\n"); d /= (double)2.0; check(); (void)fprintf(stderr, "d = %g\n", d); clear(); report("\nLONG_DOUBLE: 2^(-16384)\n"); q /= (LONG_DOUBLE)2.0; check(); (void)fprintf(stderr, "q = %Lg\n", q); separator(); report("\nTest of subnormal underflow limit\n"); clear(); report("\nfloat: 2^(-149)\n"); f = fpow((float)2.0, -149); check(); (void)fprintf(stderr, "f = %g\n", (double)f); clear(); report("\ndouble: 2^(-1074)\n"); d = dpow(2.0, -1074); check(); (void)fprintf(stderr, "d = %g\n", d); clear(); report("\nLONG_DOUBLE: 2^(-16494)\n"); q = qpow((LONG_DOUBLE)2.0, -16494); check(); (void)fprintf(stderr, "q = %Lg\n", q); separator(); report("\nTest of divide-by-two at subnormal underflow limit\n"); clear(); report("\nfloat: 2^(-150)\n"); f /= (float)2.0; check(); (void)fprintf(stderr, "f = %g\n", (double)f); clear(); report("\ndouble: 2^(-1075)\n"); d /= 2.0; check(); (void)fprintf(stderr, "d = %g\n", d); clear(); report("\nLONG_DOUBLE: 2^(-16495)\n"); q /= (LONG_DOUBLE)2.0; check(); (void)fprintf(stderr, "q = %Lg\n", q); separator(); clear(); return (EXIT_SUCCESS); } void check(VOID_ARG) { fp_except flags; flags = fpgetsticky(); if (flags) (void)fprintf(stderr,"flags = 0x%02x\n", (unsigned int)flags); if (flags & FP_X_INV) report("flag: invalid operation\n"); if (flags & FP_X_OFL) report("flag: overflow\n"); if (flags & FP_X_UFL) report("flag: underflow\n"); if (flags & FP_X_DZ) report("flag: divide-by-zero\n"); if (flags & FP_X_IMP) report("flag: precision loss\n"); } void clear(VOID_ARG) { (void)fpsetsticky(0); } #if STDC double dpow(double d, int p) #else double dpow(d,p) double d; int p; #endif { double result; result = 1.0; if (p >= 0) { while (p-- > 0) result *= d; } else { while (p++ < 0) result /= d; } return (result); } #if STDC float fpow(float f, int p) #else float fpow(f,p) float f; int p; #endif { float result; result = (float)1.0; if (p >= 0) { while (p-- > 0) result *= f; } else { while (p++ < 0) result /= f; } return (result); } #if STDC LONG_DOUBLE qpow(LONG_DOUBLE q, int p) #else LONG_DOUBLE qpow(q,p) LONG_DOUBLE q; int p; #endif { LONG_DOUBLE result; result = (LONG_DOUBLE)1.0; if (p >= 0) { while (p-- > 0) result *= q; } else { while (p++ < 0) result /= q; } return (result); } #if STDC void report(const char *s) #else void report(s) const char *s; #endif { (void)fprintf(stderr,"%s",s); } void separator(VOID_ARG) { report("------------------------------------------------------------------------\n"); }