/* This module contains a program to test Apple's implementation of the C standard functions nanf, nan, and nanl. $Revision: 1.2 $, $Date: 2005/06/16 20:14:10 $ This program tests our implementation and not just the C standard. That is, it expects the functions to return specific values we have defined where the standard allows more flexibility. This program expects that NaNs are supported; it does not check this. (Support for NaNs could be tested by checking whether the nan function returns a zero instead of a nan, whether strtod("NAN", &EndPointer) sets EndPointer to point to the first "N" rather than the terminating NULL, or whether gcc's preprocessor identifiers __FLT_HAS_QUIET_NAN__, __DBL__HAS_QUIET_NAN__, and __LDBL__HAS_QUIET_NAN__ are not defined.) This program assumes PowerPC systems are big-endian and IA-32 systems are little-endian. */ #include #include #include #include #include #include #include #include #pragma STDC FENV_ACCESS ON // Determine how many bits are in the significand of a long double. #if defined __POWERPC__ /* On a PowerPC with Apple's GCC, a long double is represented with one or two doubles. In either case, only the significand of one double is used as the significand for the long double. */ #define BitsPerLongDoubleSignificand 52 #elif defined __i386__ /* On IA-32, a long double has a 63-bit significand (just the fraction part, not including the integer bit). */ #define BitsPerLongDoubleSignificand 63 #else #error "I do not know what kind of freaky architecture you are using." #endif /* We will watch for a floating-point exception. When one occurs, the signal handler will communicate that to the regular code by setting SignalOccurred to the number of the signal that occurred (SIGFPE). */ static volatile sig_atomic_t SignalOccurred = 0; // When a signal is received, record it. static void Handler(int signal) { SignalOccurred = signal; } /* Define a large integer type for holding significands of floating-point numbers. */ typedef uint64_t Significand; /* Define a structure to hold test program context. For now, we just need to know how many errors have been found. */ typedef struct { unsigned int errors; } Context; // Extract the significand from a float. static uint64_t ExtractSignificandF(float x) { union { float f; uint32_t u; } t = { x }; return t.u & (1<<23)-1; } // Extract the significand from a double. static uint64_t ExtractSignificandD(double x) { union { double d; uint64_t u; } t = { x }; return t.u & (UINT64_C(1)<<52)-1; } // Extract the significand from a long double. static uint64_t ExtractSignificandL(long double x) { #if defined __POWERPC__ union { double ld; uint64_t u; } t = { x }; return t.u & (UINT64_C(1)<<52)-1; #elif defined __i386__ union { long double ld; struct { uint64_t IntegerAndSignificand; unsigned int : 1+15; } s; } t = { x }; return t.s.IntegerAndSignificand & (UINT64_C(1)<<63)-1; #else #error "I do not know what kind of freaky architecture you are using." #endif } /* Return true if an except occurred, indicated either by a signal or by a floating-point environment flag. */ bool DidExceptionOccur(void) { bool result = false; // Check for and reset signal. if (SignalOccurred != 0) { result = true; SignalOccurred = 0; } // Check for and reset floating-point environment flags. if (fetestexcept(FE_ALL_EXCEPT)) { result = true; /* Signaling NaNs might generated an invalid exception. Other exceptions would be more puzzling. */ if (fetestexcept(FE_ALL_EXCEPT & ~FE_INVALID)) fprintf(stderr, "Error, received floating-point exception other than invalid.\n"); feclearexcept(FE_ALL_EXCEPT); } return result; } // Test a float to see if it is not the expected NaN. static int testf(Context *context, const char *tagp, Significand expected) { float f = nanf(tagp); uint64_t observed = ExtractSignificandF(f); if (f <= 0 || 0 < f) { printf( "Error, nanf(\"%s\") returned object that is not a NaN: %.8g.\n", tagp, f); ++context->errors; return 1; } if (DidExceptionOccur()) { printf("\ Error, nanf(\"%s\") returned signaling NaN:\n\ Observed significand = 0x%" PRIx64 ".\n\ Expected significand = 0x%" PRIx64 ".\n", tagp, observed, expected); ++context->errors; return 1; } if (observed != expected) { printf("\ Error, nanf(\"%s\") returned object with unexpected significand:\n\ Observed significand = 0x%" PRIx64 ".\n\ Expected significand = 0x%" PRIx64 ".\n", tagp, observed, expected); ++context->errors; return 1; } return 0; } // Test a double to see if it is not the expected NaN. static int testd(Context *context, const char *tagp, Significand expected) { double d = nan(tagp); uint64_t observed = ExtractSignificandD(d); if (d <= 0 || 0 < d) { printf( "Error, nan(\"%s\") returned object that is not a NaN: %.17g.\n", tagp, d); ++context->errors; return 1; } if (DidExceptionOccur()) { printf("\ Error, nan(\"%s\") returned signaling NaN:\n\ Observed significand = 0x%" PRIx64 ".\n\ Expected significand = 0x%" PRIx64 ".\n", tagp, observed, expected); ++context->errors; return 1; } if (observed != expected) { printf("\ Error, nan(\"%s\") returned object with unexpected significand:\n\ Observed significand = 0x%" PRIx64 ".\n\ Expected significand = 0x%" PRIx64 ".\n", tagp, observed, expected); ++context->errors; return 1; } return 0; } // Test a long double to see if it is not the expected NaN. static int testl(Context *context, const char *tagp, Significand expected) { long double ld = nanl(tagp); uint64_t observed = ExtractSignificandL(ld); if (ld <= 0 || 0 < ld) { printf( "Error, nanl(\"%s\") returned object that is not a NaN: %.33Lg.\n", tagp, ld); ++context->errors; return 1; } if (DidExceptionOccur()) { printf("\ Error, nanl(\"%s\") returned signaling NaN:\n\ Observed significand = 0x%" PRIx64 ".\n\ Expected significand = 0x%" PRIx64 ".\n", tagp, observed, expected); ++context->errors; return 1; } if (observed != expected) { printf("\ Error, nanl(\"%s\") returned object with unexpected significand:\n\ Observed significand = 0x%" PRIx64 ".\n\ Expected significand = 0x%" PRIx64 ".\n", tagp, observed, expected); ++context->errors; return 1; } return 0; } #define QuietF(a) (UINT64_C(1)<<22 | (a)) #define QuietD(a) (UINT64_C(1)<<51 | (a)) #define QuietL(a) (UINT64_C(1)<