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; | |
| }
 |