xref: /openbsd-src/lib/libm/src/math_private.h (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
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