1 /* $OpenBSD: math_private.h,v 1.11 2008/12/09 20:00:35 martynas Exp $ */ 2 /* 3 * ==================================================== 4 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 5 * 6 * Developed at SunPro, a Sun Microsystems, Inc. business. 7 * Permission to use, copy, modify, and distribute this 8 * software is freely granted, provided that this notice 9 * is preserved. 10 * ==================================================== 11 */ 12 13 /* 14 * from: @(#)fdlibm.h 5.1 93/09/24 15 */ 16 17 #ifndef _MATH_PRIVATE_H_ 18 #define _MATH_PRIVATE_H_ 19 20 #include <sys/types.h> 21 22 /* The original fdlibm code used statements like: 23 n0 = ((*(int*)&one)>>29)^1; * index of high word * 24 ix0 = *(n0+(int*)&x); * high word of x * 25 ix1 = *((1-n0)+(int*)&x); * low word of x * 26 to dig two 32 bit words out of the 64 bit IEEE floating point 27 value. That is non-ANSI, and, moreover, the gcc instruction 28 scheduler gets it wrong. We instead use the following macros. 29 Unlike the original code, we determine the endianness at compile 30 time, not at run time; I don't see much benefit to selecting 31 endianness at run time. */ 32 33 /* A union which permits us to convert between a double and two 32 bit 34 ints. */ 35 36 /* 37 * The arm32 port is little endian except for the FP word order which is 38 * big endian. 39 */ 40 41 #if (BYTE_ORDER == BIG_ENDIAN) || defined(arm32) 42 43 typedef union 44 { 45 double value; 46 struct 47 { 48 u_int32_t msw; 49 u_int32_t lsw; 50 } parts; 51 } ieee_double_shape_type; 52 53 typedef union 54 { 55 long double value; 56 struct { 57 u_int32_t msw; 58 u_int32_t nsw; 59 u_int32_t lsw; 60 } parts; 61 } ieee_extended_shape_type; 62 63 typedef union 64 { 65 long double value; 66 struct { 67 u_int32_t mswhi; 68 u_int32_t mswlo; 69 u_int32_t lswhi; 70 u_int32_t lswlo; 71 } parts; 72 } ieee_quad_shape_type; 73 74 #endif 75 76 #if (BYTE_ORDER == LITTLE_ENDIAN) && !defined(arm32) 77 78 typedef union 79 { 80 double value; 81 struct 82 { 83 u_int32_t lsw; 84 u_int32_t msw; 85 } parts; 86 } ieee_double_shape_type; 87 88 typedef union 89 { 90 long double value; 91 struct { 92 u_int32_t lswlo; 93 u_int32_t lswhi; 94 u_int32_t mswlo; 95 u_int32_t mswhi; 96 } parts; 97 } ieee_quad_shape_type; 98 99 typedef union 100 { 101 long double value; 102 struct { 103 u_int32_t lsw; 104 u_int32_t nsw; 105 u_int32_t msw; 106 } parts; 107 } ieee_extended_shape_type; 108 109 #endif 110 111 /* Get two 32 bit ints from a double. */ 112 113 #define EXTRACT_WORDS(ix0,ix1,d) \ 114 do { \ 115 ieee_double_shape_type ew_u; \ 116 ew_u.value = (d); \ 117 (ix0) = ew_u.parts.msw; \ 118 (ix1) = ew_u.parts.lsw; \ 119 } while (0) 120 121 /* Get the more significant 32 bit int from a double. */ 122 123 #define GET_HIGH_WORD(i,d) \ 124 do { \ 125 ieee_double_shape_type gh_u; \ 126 gh_u.value = (d); \ 127 (i) = gh_u.parts.msw; \ 128 } while (0) 129 130 /* Get the less significant 32 bit int from a double. */ 131 132 #define GET_LOW_WORD(i,d) \ 133 do { \ 134 ieee_double_shape_type gl_u; \ 135 gl_u.value = (d); \ 136 (i) = gl_u.parts.lsw; \ 137 } while (0) 138 139 /* Set a double from two 32 bit ints. */ 140 141 #define INSERT_WORDS(d,ix0,ix1) \ 142 do { \ 143 ieee_double_shape_type iw_u; \ 144 iw_u.parts.msw = (ix0); \ 145 iw_u.parts.lsw = (ix1); \ 146 (d) = iw_u.value; \ 147 } while (0) 148 149 /* Set the more significant 32 bits of a double from an int. */ 150 151 #define SET_HIGH_WORD(d,v) \ 152 do { \ 153 ieee_double_shape_type sh_u; \ 154 sh_u.value = (d); \ 155 sh_u.parts.msw = (v); \ 156 (d) = sh_u.value; \ 157 } while (0) 158 159 /* Set the less significant 32 bits of a double from an int. */ 160 161 #define SET_LOW_WORD(d,v) \ 162 do { \ 163 ieee_double_shape_type sl_u; \ 164 sl_u.value = (d); \ 165 sl_u.parts.lsw = (v); \ 166 (d) = sl_u.value; \ 167 } while (0) 168 169 /* A union which permits us to convert between a float and a 32 bit 170 int. */ 171 172 typedef union 173 { 174 float value; 175 u_int32_t word; 176 } ieee_float_shape_type; 177 178 /* Get a 32 bit int from a float. */ 179 180 #define GET_FLOAT_WORD(i,d) \ 181 do { \ 182 ieee_float_shape_type gf_u; \ 183 gf_u.value = (d); \ 184 (i) = gf_u.word; \ 185 } while (0) 186 187 /* Set a float from a 32 bit int. */ 188 189 #define SET_FLOAT_WORD(d,i) \ 190 do { \ 191 ieee_float_shape_type sf_u; \ 192 sf_u.word = (i); \ 193 (d) = sf_u.value; \ 194 } while (0) 195 196 #ifdef FLT_EVAL_METHOD 197 /* 198 * Attempt to get strict C99 semantics for assignment with non-C99 compilers. 199 */ 200 #if FLT_EVAL_METHOD == 0 || __GNUC__ == 0 201 #define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval)) 202 #else /* FLT_EVAL_METHOD == 0 || __GNUC__ == 0 */ 203 #define STRICT_ASSIGN(type, lval, rval) do { \ 204 volatile type __lval; \ 205 \ 206 if (sizeof(type) >= sizeof(double)) \ 207 (lval) = (rval); \ 208 else { \ 209 __lval = (rval); \ 210 (lval) = __lval; \ 211 } \ 212 } while (0) 213 #endif /* FLT_EVAL_METHOD == 0 || __GNUC__ == 0 */ 214 #endif /* FLT_EVAL_METHOD */ 215 216 /* fdlibm kernel function */ 217 extern int __ieee754_rem_pio2(double,double*); 218 extern double __kernel_sin(double,double,int); 219 extern double __kernel_cos(double,double); 220 extern double __kernel_tan(double,double,int); 221 extern int __kernel_rem_pio2(double*,double*,int,int,int); 222 223 /* float versions of fdlibm kernel functions */ 224 extern int __ieee754_rem_pio2f(float,float*); 225 extern float __kernel_sinf(float,float,int); 226 extern float __kernel_cosf(float,float); 227 extern float __kernel_tanf(float,float,int); 228 extern int __kernel_rem_pio2f(float*,float*,int,int,int,const int*); 229 230 /* long double precision kernel functions */ 231 long double __kernel_sinl(long double, long double, int); 232 long double __kernel_cosl(long double, long double); 233 long double __kernel_tanl(long double, long double, int); 234 235 /* 236 * Common routine to process the arguments to nan(), nanf(), and nanl(). 237 */ 238 void _scan_nan(uint32_t *__words, int __num_words, const char *__s); 239 240 /* 241 * TRUNC() is a macro that sets the trailing 27 bits in the mantissa 242 * of an IEEE double variable to zero. It must be expression-like 243 * for syntactic reasons, and we implement this expression using 244 * an inline function instead of a pure macro to avoid depending 245 * on the gcc feature of statement-expressions. 246 */ 247 #define TRUNC(d) (_b_trunc(&(d))) 248 249 static __inline void 250 _b_trunc(volatile double *_dp) 251 { 252 uint32_t _lw; 253 254 GET_LOW_WORD(_lw, *_dp); 255 SET_LOW_WORD(*_dp, _lw & 0xf8000000); 256 } 257 258 struct Double { 259 double a; 260 double b; 261 }; 262 263 /* 264 * Functions internal to the math package, yet not static. 265 */ 266 double __exp__D(double, double); 267 struct Double __log__D(double); 268 269 #endif /* _MATH_PRIVATE_H_ */ 270