1 /* Inline math functions for i387.
2 Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by John C. Bowman <bowman@math.ualberta.ca>, 1995.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
22 # error "Never use <bits/mathinline.h> directly; include <math.h> instead."
26 # define __MATH_INLINE __inline
28 # define __MATH_INLINE extern __inline
32 #if defined __USE_ISOC9X && defined __GNUC__ && __GNUC__ >= 2
33 /* ISO C 9X defines some macros to perform unordered comparisons. The
34 ix87 FPU supports this with special opcodes and we should use them.
35 These must not be inline functions since we have to be able to handle
36 all floating-point types. */
38 /* For the PentiumPro and more recent processors we can provide
40 # define isgreater(x, y) \
41 ({ register char __result; \
42 __asm__ ("fucomip %%st(1), %%st; seta %%al" \
43 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \
45 # define isgreaterequal(x, y) \
46 ({ register char __result; \
47 __asm__ ("fucomip %%st(1), %%st; setae %%al" \
48 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \
51 # define isless(x, y) \
52 ({ register char __result; \
53 __asm__ ("fucomip %%st(1), %%st; seta %%al" \
54 : "=a" (__result) : "u" (x), "t" (y) : "cc", "st"); \
57 # define islessequal(x, y) \
58 ({ register char __result; \
59 __asm__ ("fucomip %%st(1), %%st; setae %%al" \
60 : "=a" (__result) : "u" (x), "t" (y) : "cc", "st"); \
63 # define islessgreater(x, y) \
64 ({ register char __result; \
65 __asm__ ("fucomip %%st(1), %%st; setne %%al" \
66 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \
69 # define isunordered(x, y) \
70 ({ register char __result; \
71 __asm__ ("fucomip %%st(1), %%st; setp %%al" \
72 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \
75 /* This is the dumb, portable code for i386 and above. */
76 # define isgreater(x, y) \
77 ({ register char __result; \
78 __asm__ ("fucompp; fnstsw; testb $0x45, %%ah; setz %%al" \
79 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
82 # define isgreaterequal(x, y) \
83 ({ register char __result; \
84 __asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al" \
85 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
88 # define isless(x, y) \
89 ({ register char __result; \
90 __asm__ ("fucompp; fnstsw; testb $0x45, %%ah; setz %%al" \
91 : "=a" (__result) : "u" (x), "t" (y) : "cc", "st", "st(1)"); \
94 # define islessequal(x, y) \
95 ({ register char __result; \
96 __asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al" \
97 : "=a" (__result) : "u" (x), "t" (y) : "cc", "st", "st(1)"); \
100 # define islessgreater(x, y) \
101 ({ register char __result; \
102 __asm__ ("fucompp; fnstsw; testb $0x44, %%ah; setz %%al" \
103 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
106 # define isunordered(x, y) \
107 ({ register char __result; \
108 __asm__ ("fucompp; fnstsw; sahf; setp %%al" \
109 : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \
111 # endif /* __i686__ */
113 /* Test for negative number. Used in the signbit() macro. */
115 __signbitf (float __x
)
117 union { float __f
; int __i
; } __u
= { __f
: __x
}; return __u
.__i
< 0;
120 __signbit (double __x
)
122 union { double __d
; int __i
[2]; } __u
= { __d
: __x
}; return __u
.__i
[1] < 0;
125 __signbitl (long double __x
)
127 union { long double __l
; int __i
[3]; } __u
= { __l
: __x
};
128 return (__u
.__i
[2] & 0x8000) != 0;
133 /* The gcc, version 2.7 or below, has problems with all this inlining
134 code. So disable it for this version of the compiler. */
135 #if defined __GNUC__ && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 7))
137 #if ((!defined __NO_MATH_INLINES || defined __LIBC_INTERNAL_MATH_INLINES) \
138 && defined __OPTIMIZE__)
140 /* A macro to define float, double, and long double versions of various
141 math functions for the ix87 FPU. FUNC is the function name (which will
142 be suffixed with f and l for the float and long double version,
143 respectively). OP is the name of the FPU operation. */
145 #if defined __USE_MISC || defined __USE_ISOC9X
146 # define __inline_mathop(func, op) \
147 __inline_mathop_ (double, func, op) \
148 __inline_mathop_ (float, __CONCAT(func,f), op) \
149 __inline_mathop_ (long double, __CONCAT(func,l), op)
151 # define __inline_mathop(func, op) \
152 __inline_mathop_ (double, func, op)
155 #define __inline_mathop_(float_type, func, op) \
156 __inline_mathop_decl_ (float_type, func, op, "0" (__x))
159 #if defined __USE_MISC || defined __USE_ISOC9X
160 # define __inline_mathop_decl(func, op, params...) \
161 __inline_mathop_decl_ (double, func, op, params) \
162 __inline_mathop_decl_ (float, __CONCAT(func,f), op, params) \
163 __inline_mathop_decl_ (long double, __CONCAT(func,l), op, params)
165 # define __inline_mathop_decl(func, op, params...) \
166 __inline_mathop_decl_ (double, func, op, params)
169 #define __inline_mathop_decl_(float_type, func, op, params...) \
170 __MATH_INLINE float_type func (float_type); \
171 __MATH_INLINE float_type func (float_type __x) \
173 register float_type __result; \
174 __asm __volatile__ (op : "=t" (__result) : params); \
179 #if defined __USE_MISC || defined __USE_ISOC9X
180 # define __inline_mathcode(func, arg, code) \
181 __inline_mathcode_ (double, func, arg, code) \
182 __inline_mathcode_ (float, __CONCAT(func,f), arg, code) \
183 __inline_mathcode_ (long double, __CONCAT(func,l), arg, code)
184 # define __inline_mathcode2(func, arg1, arg2, code) \
185 __inline_mathcode2_ (double, func, arg1, arg2, code) \
186 __inline_mathcode2_ (float, __CONCAT(func,f), arg1, arg2, code) \
187 __inline_mathcode2_ (long double, __CONCAT(func,l), arg1, arg2, code)
188 # define __inline_mathcode3(func, arg1, arg2, arg3, code) \
189 __inline_mathcode3_ (double, func, arg1, arg2, arg3, code) \
190 __inline_mathcode3_ (float, __CONCAT(func,f), arg1, arg2, arg3, code) \
191 __inline_mathcode3_ (long double, __CONCAT(func,l), arg1, arg2, arg3, code)
193 # define __inline_mathcode(func, arg, code) \
194 __inline_mathcode_ (double, func, (arg), code)
195 # define __inline_mathcode2(func, arg1, arg2, code) \
196 __inline_mathcode2_ (double, func, arg1, arg2, code)
197 # define __inline_mathcode3(func, arg1, arg2, arg3, code) \
198 __inline_mathcode3_ (double, func, arg1, arg2, arg3, code)
201 #define __inline_mathcode_(float_type, func, arg, code) \
202 __MATH_INLINE float_type func (float_type); \
203 __MATH_INLINE float_type func (float_type arg) \
208 #define __inline_mathcode2_(float_type, func, arg1, arg2, code) \
209 __MATH_INLINE float_type func (float_type, float_type); \
210 __MATH_INLINE float_type func (float_type arg1, float_type arg2) \
215 #define __inline_mathcode3_(float_type, func, arg1, arg2, arg3, code) \
216 __MATH_INLINE float_type func (float_type, float_type, float_type); \
217 __MATH_INLINE float_type func (float_type arg1, float_type arg2, \
225 #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
226 /* Miscellaneous functions */
228 __inline_mathcode (__sgn
, __x
, \
229 return __x
== 0.0 ? 0.0 : (__x
> 0.0 ? 1.0 : -1.0))
231 __inline_mathcode (__pow2
, __x
, \
232 register long double __value
; \
233 register long double __exponent
; \
234 __extension__
long long int __p
= (long long int) __x
; \
235 if (__x
== (long double) __p
) \
239 : "=t" (__value
) : "0" (1.0), "u" (__x
)); \
243 ("fldl %%st(0)\n\t" \
244 "frndint # int(x)\n\t" \
246 "fsub %%st(1) # fract(x)\n\t" \
247 "f2xm1 # 2^(fract(x)) - 1\n\t" \
248 : "=t" (__value
), "=u" (__exponent
) : "0" (__x
)); \
252 : "=t" (__value
) : "0" (__value
), "u" (__exponent
)); \
255 #define __sincos_code \
256 register long double __cosr; \
257 register long double __sinr; \
261 "testl $0x400, %%eax\n\t" \
268 "testl $0x400, %%eax\n\t" \
273 : "=t" (__cosr), "=u" (__sinr) : "0" (__x)); \
277 __MATH_INLINE
void __sincos (double __x
, double *__sinx
, double *__cosx
);
279 __sincos (double __x
, double *__sinx
, double *__cosx
)
284 __MATH_INLINE
void __sincosf (float __x
, float *__sinx
, float *__cosx
);
286 __sincosf (float __x
, float *__sinx
, float *__cosx
)
291 __MATH_INLINE
void __sincosl (long double __x
, long double *__sinx
,
292 long double *__cosx
);
294 __sincosl (long double __x
, long double *__sinx
, long double *__cosx
)
300 /* Optimized inline implementation, sometimes with reduced precision
301 and/or argument range. */
303 #define __expm1_code \
304 register long double __value; \
305 register long double __exponent; \
306 register long double __temp; \
308 ("fldl2e # e^x - 1 = 2^(x * log2(e)) - 1\n\t" \
309 "fmul %%st(1) # x * log2(e)\n\t" \
311 "frndint # int(x * log2(e))\n\t" \
313 "fsub %%st(1) # fract(x * log2(e))\n\t" \
314 "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \
315 "fscale # 2^(x * log2(e)) - 2^(int(x * log2(e)))\n\t" \
316 : "=t" (__value), "=u" (__exponent) : "0" (__x)); \
318 ("fscale # 2^int(x * log2(e))\n\t" \
319 : "=t" (__temp) : "0" (1.0), "u" (__exponent)); \
321 return __temp + __value
322 __inline_mathcode_ (long double, __expm1l
, __x
, __expm1_code
)
326 register long double __value; \
327 register long double __exponent; \
329 ("fldl2e # e^x = 2^(x * log2(e))\n\t" \
330 "fmul %%st(1) # x * log2(e)\n\t" \
332 "frndint # int(x * log2(e))\n\t" \
334 "fsub %%st(1) # fract(x * log2(e))\n\t" \
335 "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \
336 : "=t" (__value), "=u" (__exponent) : "0" (__x)); \
340 : "=t" (__value) : "0" (__value), "u" (__exponent)); \
342 __inline_mathcode (exp
, __x
, __exp_code
)
343 __inline_mathcode_ (long double, __expl
, __x
, __exp_code
)
346 __inline_mathcode (tan
, __x
, \
347 register long double __value
; \
348 register long double __value2
__attribute__ ((__unused__
)); \
351 : "=t" (__value2
), "=u" (__value
) : "0" (__x
)); \
355 #define __atan2_code \
356 register long double __value; \
359 : "=t" (__value) : "0" (__x), "u" (__y) : "st(1)"); \
361 __inline_mathcode2 (atan2
, __y
, __x
, __atan2_code
)
362 __inline_mathcode2_ (long double, __atan2l
, __y
, __x
, __atan2_code
)
365 __inline_mathcode2 (fmod
, __x
, __y
, \
366 register long double __value
; \
372 : "=t" (__value
) : "0" (__x
), "u" (__y
) : "ax", "cc"); \
376 __inline_mathcode2 (pow
, __x
, __y
, \
377 register long double __value
; \
378 register long double __exponent
; \
379 __extension__
long long int __p
= (long long int) __y
; \
380 if (__x
== 0.0 && __y
> 0.0) \
382 if (__y
== (double) __p
) \
384 long double __r
= 1.0; \
404 ("fyl2x" : "=t" (__value
) : "0" (__x
), "u" (1.0) : "st(1)"); \
406 ("fmul %%st(1) # y * log2(x)\n\t" \
408 "frndint # int(y * log2(x))\n\t" \
410 "fsub %%st(1) # fract(y * log2(x))\n\t" \
411 "f2xm1 # 2^(fract(y * log2(x))) - 1\n\t" \
412 : "=t" (__value
), "=u" (__exponent
) : "0" (__y
), "1" (__value
)); \
416 : "=t" (__value
) : "0" (__value
), "u" (__exponent
)); \
420 __inline_mathop (sqrt
, "fsqrt")
421 __inline_mathop_ (long double, __sqrtl
, "fsqrt")
423 #if defined __GNUC__ && (__GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 8)
424 __inline_mathcode_ (double, fabs
, __x
, return __builtin_fabs (__x
))
425 __inline_mathcode_ (float, fabsf
, __x
, return __builtin_fabsf (__x
))
426 __inline_mathcode_ (long double, fabsl
, __x
, return __builtin_fabsl (__x
))
427 __inline_mathcode_ (long double, __fabsl
, __x
, return __builtin_fabsl (__x
))
429 __inline_mathop (fabs
, "fabs")
430 __inline_mathop_ (long double, __fabsl
, "fabs")
433 /* The argument range of this inline version is reduced. */
434 __inline_mathop (sin
, "fsin")
435 /* The argument range of this inline version is reduced. */
436 __inline_mathop (cos
, "fcos")
438 __inline_mathop (atan
, "fld1; fpatan")
439 __inline_mathop (log
, "fldln2; fxch; fyl2x")
440 __inline_mathop (log10
, "fldlg2; fxch; fyl2x")
442 __inline_mathcode (asin
, __x
, return __atan2l (__x
, __sqrtl (1.0 - __x
* __x
)))
443 __inline_mathcode (acos
, __x
, return __atan2l (__sqrtl (1.0 - __x
* __x
), __x
))
445 __inline_mathcode_ (long double, __sgn1l
, __x
, return __x
>= 0.0 ? 1.0 : -1.0)
448 /* The argument range of the inline version of sinhl is slightly reduced. */
449 __inline_mathcode (sinh
, __x
, \
450 register long double __exm1
= __expm1l (__fabsl (__x
)); \
451 return 0.5 * (__exm1
/ (__exm1
+ 1.0) + __exm1
) * __sgn1l (__x
))
453 __inline_mathcode (cosh
, __x
, \
454 register long double __ex
= __expl (__x
); \
455 return 0.5 * (__ex
+ 1.0 / __ex
))
457 __inline_mathcode (tanh
, __x
, \
458 register long double __exm1
= __expm1l (-__fabsl (__x
+ __x
)); \
459 return __exm1
/ (__exm1
+ 2.0) * __sgn1l (-__x
))
462 __inline_mathcode (floor
, __x
, \
463 register long double __value
; \
464 __volatile
unsigned short int __cw
; \
465 __volatile
unsigned short int __cwtmp
; \
466 __asm
__volatile ("fnstcw %0" : "=m" (__cw
)); \
467 __cwtmp
= (__cw
& 0xf3ff) | 0x0400; /* rounding down */ \
468 __asm
__volatile ("fldcw %0" : : "m" (__cwtmp
)); \
469 __asm
__volatile ("frndint" : "=t" (__value
) : "0" (__x
)); \
470 __asm
__volatile ("fldcw %0" : : "m" (__cw
)); \
473 __inline_mathcode (ceil
, __x
, \
474 register long double __value
; \
475 __volatile
unsigned short int __cw
; \
476 __volatile
unsigned short int __cwtmp
; \
477 __asm
__volatile ("fnstcw %0" : "=m" (__cw
)); \
478 __cwtmp
= (__cw
& 0xf3ff) | 0x0800; /* rounding up */ \
479 __asm
__volatile ("fldcw %0" : : "m" (__cwtmp
)); \
480 __asm
__volatile ("frndint" : "=t" (__value
) : "0" (__x
)); \
481 __asm
__volatile ("fldcw %0" : : "m" (__cw
)); \
484 #define __ldexp_code \
485 register long double __value; \
488 : "=t" (__value) : "0" (__x), "u" ((long double) __y)); \
491 __MATH_INLINE
double ldexp (double __x
, int __y
);
493 ldexp (double __x
, int __y
)
499 /* Optimized versions for some non-standardized functions. */
500 #if defined __USE_ISOC9X || defined __USE_MISC
502 __inline_mathop(log2
, "fld1; fxch; fyl2x")
504 __inline_mathcode (expm1
, __x
, __expm1_code
)
506 /* We cannot rely on M_SQRT being defined. So we do it for ourself
508 # define __M_SQRT2 1.41421356237309504880L /* sqrt(2) */
510 __inline_mathcode (log1p
, __x
, \
511 register long double __value
; \
512 if (__fabsl (__x
) >= 1.0 - 0.5 * __M_SQRT2
) \
513 __value
= logl (1.0 + __x
); \
519 : "=t" (__value
) : "0" (__x
)); \
523 /* The argument range of the inline version of asinhl is slightly reduced. */
524 __inline_mathcode (asinh
, __x
, \
525 register long double __y
= __fabsl (__x
); \
526 return (log1pl (__y
* __y
/ (__sqrtl (__y
* __y
+ 1.0) + 1.0) + __y
) \
529 __inline_mathcode (acosh
, __x
, \
530 return logl (__x
+ __sqrtl (__x
- 1.0) * __sqrtl (__x
+ 1.0)))
532 __inline_mathcode (atanh
, __x
, \
533 register long double __y
= __fabsl (__x
); \
534 return -0.5 * log1pl (-(__y
+ __y
) / (1.0 + __y
)) * __sgn1l (__x
))
537 /* The argument range of the inline version of hypotl is slightly reduced. */
538 __inline_mathcode2 (hypot
, __x
, __y
, return __sqrtl (__x
* __x
+ __y
* __y
))
540 __inline_mathcode(logb
, __x
, \
541 register long double __value
; \
542 register long double __junk
; \
545 : "=t" (__junk
), "=u" (__value
) : "0" (__x
)); \
548 __MATH_INLINE
float ldexpf (float __x
, int __y
);
550 ldexpf (float __x
, int __y
)
555 __MATH_INLINE
long double ldexpl (long double __x
, int __y
);
556 __MATH_INLINE
long double
557 ldexpl (long double __x
, int __y
)
562 __inline_mathcode3 (fma
, __x
, __y
, __z
, return (__x
* __y
) + __z
)
568 __inline_mathcode2 (drem
, __x
, __y
, \
569 register double __value
; \
575 : "=t" (__value
) : "0" (__x
), "u" (__y
) : "ax", "cc"); \
579 /* This function is used in the `isfinite' macro. */
580 __MATH_INLINE
int __finite (double __x
) __attribute__ ((__const__
));
582 __finite (double __x
)
584 return (__extension__
585 (((((union { double __d
; int __i
[2]; }) {__d
: __x
}).__i
[1]
586 | 0x800fffff) + 1) >> 31));
589 /* Miscellaneous functions */
591 __inline_mathcode (__coshm1
, __x
, \
592 register long double __exm1
= __expm1l (__fabsl (__x
)); \
593 return 0.5 * (__exm1
/ (__exm1
+ 1.0)) * __exm1
)
595 __inline_mathcode (__acosh1p
, __x
, \
596 return log1pl (__x
+ __sqrtl (__x
) * __sqrtl (__x
+ 2.0)))
598 #endif /* __USE_MISC */
600 /* Undefine some of the large macros which are not used anymore. */
606 #endif /* __NO_MATH_INLINES */
609 /* This code is used internally in the GNU libc. */
610 #ifdef __LIBC_INTERNAL_MATH_INLINES
611 __inline_mathop (__ieee754_sqrt
, "fsqrt")
612 __inline_mathcode2 (__ieee754_atan2
, __y
, __x
,
613 register long double __value
;
614 __asm
__volatile__ ("fpatan\n\t"
616 : "0" (__x
), "u" (__y
) : "st(1)");
620 #endif /* __GNUC__ */