xref: /openbsd-src/lib/libm/src/math_private.h (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenBSD: math_private.h,v 1.10 2008/09/07 20:36:09 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
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
214 #endif
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,const 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 /*
231  * TRUNC() is a macro that sets the trailing 27 bits in the mantissa
232  * of an IEEE double variable to zero.  It must be expression-like
233  * for syntactic reasons, and we implement this expression using
234  * an inline function instead of a pure macro to avoid depending
235  * on the gcc feature of statement-expressions.
236  */
237 #define TRUNC(d)	(_b_trunc(&(d)))
238 
239 static __inline void
240 _b_trunc(volatile double *_dp)
241 {
242 	uint32_t _lw;
243 
244 	GET_LOW_WORD(_lw, *_dp);
245 	SET_LOW_WORD(*_dp, _lw & 0xf8000000);
246 }
247 
248 struct Double {
249 	double	a;
250 	double	b;
251 };
252 
253 /*
254  * Functions internal to the math package, yet not static.
255  */
256 double __exp__D(double, double);
257 struct Double __log__D(double);
258 
259 #endif /* _MATH_PRIVATE_H_ */
260