You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							120 lines
						
					
					
						
							4.3 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							120 lines
						
					
					
						
							4.3 KiB
						
					
					
				
								/* Determine some float parameters, much like gcc's "enquire.c". */
							 | 
						|
								/* Bruno Haible 24.8.1996 */
							 | 
						|
								
							 | 
						|
								/* This program expects to be compiled by an ANSI C or C++ compiler. */
							 | 
						|
								
							 | 
						|
								#include <stdio.h>
							 | 
						|
								
							 | 
						|
								#if !(defined(__STDC__) || defined(__cplusplus))
							 | 
						|
								/* Only for use in function parameter lists and as function return type. */
							 | 
						|
								#define void
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								typedef int boolean;
							 | 
						|
								#define TRUE  1
							 | 
						|
								#define FALSE 0
							 | 
						|
								
							 | 
						|
								#ifdef HAVE_LONGDOUBLE
							 | 
						|
								typedef long double ldouble;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								static void header (void)
							 | 
						|
								{
							 | 
						|
								  printf("/* Rounding modes, for use below */\n");
							 | 
						|
								  printf("#define rounds_to_nearest        0  /* 0.5 ulp */\n");
							 | 
						|
								  printf("#define rounds_to_zero           1  /* 1 ulp */\n");
							 | 
						|
								  printf("#define rounds_to_infinity       2  /* 1 ulp */\n");
							 | 
						|
								  printf("#define rounds_to_minus_infinity 3  /* 1 ulp */\n");
							 | 
						|
								  printf("\n");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								#define check(type,typeprefix,typestr,equalfn,mainfn)  \
							 | 
						|
								static boolean equalfn (type* x, type* y);				\
							 | 
						|
								static void mainfn (void)						\
							 | 
						|
								{									\
							 | 
						|
								  int mant_bits;							\
							 | 
						|
								  int epsilon_bits = -1;						\
							 | 
						|
								  int negepsilon_bits = -1;						\
							 | 
						|
								  { type x = 1.0; type y; type z;					\
							 | 
						|
								    for (y = 1.0; ; y = 0.5*y)						\
							 | 
						|
								      { z = x + y; if (equalfn(&x,&z)) break;				\
							 | 
						|
								        z = z - x; if (!equalfn(&y,&z)) break;				\
							 | 
						|
								        epsilon_bits++;							\
							 | 
						|
								  }   }									\
							 | 
						|
								  { type x = 1.0; type y; type z;					\
							 | 
						|
								    for (y = -1.0; ; y = 0.5*y)						\
							 | 
						|
								      { z = x + y; if (equalfn(&x,&z)) break;				\
							 | 
						|
								        z = z - x; if (!equalfn(&y,&z)) break;				\
							 | 
						|
								        negepsilon_bits++;						\
							 | 
						|
								  }   }									\
							 | 
						|
								  printf("/* Properties of type `%s': */\n",typestr);			\
							 | 
						|
								  printf("/* Largest n for which 1+2^(-n) is exactly represented is %d. */\n",epsilon_bits); \
							 | 
						|
								  printf("/* Largest n for which 1-2^(-n) is exactly represented is %d. */\n",negepsilon_bits); \
							 | 
						|
								  if (negepsilon_bits <= epsilon_bits)					\
							 | 
						|
								    { printf("#error \"No exponent jump at 1.0 for type %s!\"\n",typestr); \
							 | 
						|
								      mant_bits = -1;							\
							 | 
						|
								    }									\
							 | 
						|
								  else									\
							 | 
						|
								    { if (negepsilon_bits > epsilon_bits+1)				\
							 | 
						|
								        printf("/* Base for type `%s' is 2^%d\n",typestr,negepsilon_bits-epsilon_bits); \
							 | 
						|
								      mant_bits = epsilon_bits+1;					\
							 | 
						|
								      printf("#define %s_mant_bits %d\n",typeprefix,mant_bits);		\
							 | 
						|
								    }									\
							 | 
						|
								  { int i; type x, y1, y2, ys1, ys2, z1, z2, zs1, zs2;			\
							 | 
						|
								    x = 1.0; for (i = 0; i < epsilon_bits; i++) { x = 0.5*x; }		\
							 | 
						|
								    y1 = 1.0 + 5.0*x; y2 = 1.0 + 6.0*x;					\
							 | 
						|
								    ys1 = 1.0 + 5.4*x; ys2 = 1.0 + 5.6*x;				\
							 | 
						|
								    z1 = -1.0 + (-5.0)*x; z2 = -1.0 + (-6.0)*x;				\
							 | 
						|
								    zs1 = -1.0 + (-5.4)*x; zs2 = -1.0 + (-5.6)*x;			\
							 | 
						|
								    if (equalfn(&ys1,&y1) && equalfn(&ys2,&y2) && equalfn(&zs1,&z1) && equalfn(&zs2,&z2)) \
							 | 
						|
								      printf("#define %s_rounds rounds_to_nearest\n",typeprefix);	\
							 | 
						|
								    else if (equalfn(&ys1,&y1) && equalfn(&ys2,&y1) && equalfn(&zs1,&z1) && equalfn(&zs2,&z1)) \
							 | 
						|
								      printf("#define %s_rounds rounds_to_zero\n",typeprefix);		\
							 | 
						|
								    else if (equalfn(&ys1,&y2) && equalfn(&ys2,&y2) && equalfn(&zs1,&z1) && equalfn(&zs2,&z1)) \
							 | 
						|
								      printf("#define %s_rounds rounds_to_infinity\n",typeprefix);	\
							 | 
						|
								    else if (equalfn(&ys1,&y1) && equalfn(&ys2,&y1) && equalfn(&zs1,&z2) && equalfn(&zs2,&z2)) \
							 | 
						|
								      printf("#define %s_rounds rounds_to_minus_infinity\n",typeprefix); \
							 | 
						|
								    else								\
							 | 
						|
								      printf("#error \"Unknown rounding mode for type %s!\"\n",typestr); \
							 | 
						|
								  }									\
							 | 
						|
								  printf("\n");								\
							 | 
						|
								}									\
							 | 
						|
								static boolean equalfn (type* x, type* y) { return *x == *y; }		\
							 | 
						|
								
							 | 
						|
								check(float,"float","float",equal_float,main_float)
							 | 
						|
								check(double,"double","double",equal_double,main_double)
							 | 
						|
								#ifdef HAVE_LONGDOUBLE
							 | 
						|
								check(ldouble,"long_double","long double",equal_ldouble,main_ldouble)
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								/* Some systems (arm/linux) store doubles as little endian but with higher
							 | 
						|
								 * and lower word reversed. */
							 | 
						|
								static void flipped_double (void)
							 | 
						|
								{
							 | 
						|
								  typedef struct { unsigned lo, hi; } dfloat;
							 | 
						|
								  double x = 2;
							 | 
						|
								  dfloat test = *(dfloat*)&x;
							 | 
						|
								  if (test.lo==0 && test.hi!=0) {
							 | 
						|
								    printf("#define double_wordorder_bigendian_p 0\n");
							 | 
						|
								  } else if (test.lo!=0 && test.hi==0) {
							 | 
						|
								    printf("#define double_wordorder_bigendian_p 1\n");
							 | 
						|
								  } else {
							 | 
						|
								    /* Dazed and confused!  Better not define anything.
							 | 
						|
									 * Code should rely on CL_CPU_BIG_ENDIAN_P instead. */
							 | 
						|
								  }
							 | 
						|
								  printf("\n");
							 | 
						|
								}
							 | 
						|
									 
							 | 
						|
								int main()
							 | 
						|
								{
							 | 
						|
								  header();
							 | 
						|
								  main_float();
							 | 
						|
								  main_double();
							 | 
						|
								#ifdef HAVE_LONGDOUBLE
							 | 
						|
								  main_ldouble();
							 | 
						|
								#endif
							 | 
						|
								  flipped_double();
							 | 
						|
								
							 | 
						|
								  if (ferror(stdout)) return 1;
							 | 
						|
								  return 0;
							 | 
						|
								}
							 |