glibc/sysdeps/i386/fpu/__math.h
Ulrich Drepper 1f205a479b Update.
1997-05-21 02:49  Ulrich Drepper  <drepper@cygnus.com>

	* gnu-versions.h (_GNU_OBSTACK_INTERFACE_VERSION): Set to 2 since
	interface was changed with addition of _obstack_memory_used.
	Suggested by Ian Taylor <ian@cygnus.com>.

	* malloc/obstack.c: Include <config.h>.  Include <stdlib.h> only
	if __GNU_LIBRARY__ or HAVE_STDLIB_H is defined.
	Reported by Ian Taylor <ian@cygnus.com>.

	* dirent/Makefile (routines): Add versionsort.
	* dirent/dirent.h: Add prototype for versionsort.
	* dirent/versionsort.c: New file.
	* manual/filesys.texi: Add documentation for versionsort.
	* manual/string.texi: Add documentation for strverscmp.
	* string/Makefile (routines): Add strverscmp.
	(tests): Add tst-svc.
	* string/string.h: Add prototype for strverscmp.
	* string/strverscmp.c: New file.
	* string/tst-svc.c: New file.  Test for strverscmp.
	* string/tst-svc.input: New file.  Input data for tst-svc.
	* string/tst-svc.expect: New file.  Expected out from tst-svc.

	* math/Makefile (calls): Add s_signbit.

	* po/sv.po: Update.

	* resolv/nss_dns/dns-host.c: Add casts to prevent warnings.
	* sunrpc/pmap_rmt.c: Likewise.

	* string/basename.c: Don't use ISO C definition style.
	Include <config.h> is HAVE_CONFIG_H is defined.

	* sunrpc/proto.h: Add `const' wherever possible.
	* sunrpc/rpc_cout.c: Likewise.
	* sunrpc/rpc_svcout.c: Likewise.
	* sunrpc/xdr_mem.c: Likewise.
	* sunrpc/xdr_rec.c: Likewise.
	* sunrpc/xdr_stdio.c: Likewise.
	* sunrpc/rpc_parse.c: Delete comma from end of enum definition.
	* sunrpc/xdr.c: Little code cleanups.
	* sunrpc/xdr_flaot.c: Likewise.
	Patches by Matthew Wilcox <matthew.wilcox@chbs.mhs.ciba.com>.

	* sysdeps/i386/fpu/__math.h (__finite): Fix typo.

	* sysdeps/unix/sysv/linux/shmdt.c: Add cast to prevent warning.

	* time/europe: Update from tzdata1997f.
	* time/zic.c: Update from tzcode1997e.

1997-05-20 19:20  Miguel de Icaza <miguel@athena.nuclecu.unam.mx>

	* sysdeps/sparc/setjmp.S: Flush windows.
	Bug found by Richard Henderson.

1997-05-19 12:54  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* misc/efgcvt_r.c (fcvt_r, ecvt_r): Rewritten as to fit the specs.

1997-05-19 18:41  Thorsten Kukuk  <kukuk@uni-paderborn.de>

	* nis/nss_nisplus/nisplus-spwd.c (_nss_nisplus_parse_spent): Use
	atol instead of atoi.

1997-05-18 00:22  Philip Blundell <pjb27@cam.ac.uk>

	* inet/Makefile (routines): Add if_index.
	* sysdeps/unix/sysv/linux/if_index.c: New file.
	* sysdeps/stub/if_index.c: New file.
	* sysdeps/unix/sysv/linux/net/if.h: Add prototypes for routines in
	if_index.c (required by IPv6 basic API).
	* sysdeps/unix/sysv/linux/netinet/in.h: Add struct ipv6_pktinfo.

1997-05-17 23:29  Philip Blundell  <pjb27@cam.ac.uk>

	* sysdeps/unix/sysv/linux/netinet/in.h: Update IPv6 definitions
	for new advanced API draft.

1997-05-13 21:33  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* stdio-common/printf_fp.c: Only use the field width for deciding
	on padding when printing special values.
	* stdio-common/printf_fphex.c: Likewise.

1997-05-15 13:14  Miles Bader  <miles@gnu.ai.mit.edu>

	Changes by Thomas Bushnell <thomas@gnu.ai.mit.edu>:
	* hurd/hurdauth.c (_S_msg_add_auth): Implement correctly.

1997-05-12 14:50  Thomas Bushnell, n/BSG  <thomas@gnu.ai.mit.edu>

	* hurd/hurdsig.c (_hurdsig_init): Double size of sigthread stack;
	msg_add_auth was overflowing it.

1997-05-12 21:20  Richard Henderson  <rth@tamu.edu>

	* elf/dl-lookup.c (_dl_lookup_symbol_skip): Call _dl_signal_error
	when we can't find the symbol.

1997-05-12 16:54  Ulrich Drepper  <drepper@cygnus.com>

	* posix/regex.c: Fix handling of 32-bit Windog environments.
	Patch by Arnold Robbins <arnold@skeeve.atl.ga.us>.

1997-05-10 23:26  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/unix/sysv/linux/m68k/syscalls.list: Add cacheflush.

1997-05-10 11:40  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* elf/ldd.bash.in: Remove spurious quote character from version
	message.

1997-05-10 08:49  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* locale/programs/locale.c (write_charmaps): Don't get stuck in a
	loop if the file ends in a long line without newline.
	* locale/programs/charmap.c (charmap_read): Likewise.

1997-05-12 03:47  Ulrich Drepper  <drepper@cygnus.com>

	* sunrpc/rpc/xdr.h: Include more headers to be self-contained.
	* sunrpc/rpc/svc_auth.h: Likewise.
	* sunrpc/rpc/svc.h: Likewise.
	* sunrpc/rpc/rpc_msg.h: Likewise.
	* sunrpc/rpc/pmap_rmt.h: Likewise.
	* sunrpc/rpc/pmap_clnt.h: Likewise.
	* sunrpc/rpc/clnt.h: Likewise.
	* sunrpc/rpc/auth_unix.h: Likewise.
	* sysdeps/generic/rpc/auth.h: Likewise.
	Patches by Michael Deutschmann <ldeutsch@mail.netshop.net>.

1997-05-11 15:29  Philip Blundell  <pjb27@cam.ac.uk>

	* sysdeps/stub/sigaction.c (__sigaction): Correct typo.
	* sysdeps/standalone/arm/errnos.h: New file.
	* sysdeps/stub/sys/param.h: Add dummy definition of MAXSYMLINKS.
	* sysdeps/unix/arm/fork.S: New file.
	* sysdeps/unix/sysv/linux/arm/sysdep.h: New file.
	* sysdeps/stub/tempname.c (__stdio_gen_tempname): Add missing
	`streamptr' argument.
	* sysdeps/stub/vdprintf.c: Remove second copy of file (!), include
	<stdarg.h> to get va_list defined, return 0 not NULL.
	* sysdeps/unix/sysv/linux/statfsbuf.h: Include <gnu/types.h>.
	* sysdeps/unix/sysv/linux/arm/syscall.S: New file.
	* sysdeps/stub/direntry.h (struct dirent): Add missing ';'.
	* sysdeps/stub/seekdir.c (seekdir): Likewise.
	* sysdeps/stub/dirfd.c (dirfd): Argument dirp is DIR*, not FILE*.
	* sysdeps/standalone/dirstream.h: Define struct __dirstream
	not DIR; <dirent.h> provides typedef.
	* sysdeps/unix/sysv/linux/arm/clone.S: New file.
	* sysdeps/unix/sysv/linux/arm/socket.S: New file.
	* sysdeps/stub/sysconf.c (__sysconf): Fix typos.

1997-05-01 06:35  Geoff Keating  <geoffk@ozemail.com.au>

	* sysdeps/powerpc/Dist: New file.
	* sysdeps/powerpc/Makefile: New file.
	* sysdeps/powerpc/fclrexcpt.c: New file.
	* sysdeps/powerpc/fegetenv.c: New file.
	* sysdeps/powerpc/fegetround.c: New file.
	* sysdeps/powerpc/feholdexcpt.c: New file.
	* sysdeps/powerpc/fenvbits.h: New file.
	* sysdeps/powerpc/fenv_const.c: New file.
	* sysdeps/powerpc/fenv_libc.h: New file.
	* sysdeps/powerpc/fesetenv.c: New file.
	* sysdeps/powerpc/fesetround.c: New file.
	* sysdeps/powerpc/feupdateenv.c: New file.
	* sysdeps/powerpc/fgetexcptflg.c: New file.
	* sysdeps/powerpc/fraiseexcpt.c: New file.
	* sysdeps/powerpc/fsetexcptflg.c: New file.
	* sysdeps/powerpc/ftestexcept.c: New file.
	* sysdeps/powerpc/mathbits.h: New file.

	* sysdeps/powerpc/dl-machine.h: Wrap in #ifndef dl_machine_h;
	define elf_machine_lookup_noexec_p, elf_machine_lookup_noplt_p,
	ELF_MACHINE_RELOC_NOPLT; consequent changes to elf_machine_rela.

	* sysdeps/powerpc/__math.h: Remove definition for hypot and __sgn.

	* sysdep/powerpc/fpu_control.h: Correct IEEE default mode.

	* sysdeps/unix/sysv/linux/powerpc/sysdep.h: Don't use .text, but
	instead .section ".text".

1997-04-25 05:06  Geoff Keating  <geoffk@ozemail.com.au>

	* sysdeps/powerpc/__longjmp.S: Use symbolic register numbering.
	* sysdeps/powerpc/bsd-_setjmp.S: Likewise.
	* sysdeps/powerpc/bsd-setjmp.S: Likewise.
	* sysdeps/powerpc/setjmp.S: Likewise.

	* sysdeps/unix/sysv/linux/clone.S: Likewise.
	* sysdeps/unix/sysv/linux/socket.S: Likewise.
	* sysdeps/unix/sysv/linux/syscall.S: Likewise.

1997-04-20 04:37  Geoff Keating  <geoffk@ozemail.com.au>

	* sysdeps/powerpc/strchr.s: New file.
	* sysdeps/powerpc/strcmp.s: New (ugly) file.
	* sysdeps/powerpc/memset.s: New file.
	* string/tester.c: Include prototype and _GNU_SOURCE to make
	standalone compilation possible. Give strcmp a better
	test. Give memset a better test.

1997-04-05 06:34  Geoff Keating  <geoffk@ozemail.com.au>

	* sysdeps/powerpc/strlen.s: Fixed bugs (how did it ever pass its
	tests before?). Changed to symbolic register numbering as an
	experiment.
	* sysdeps/powerpc/ffs.c: Don't include bstring.h, it doesn't
	exist.
	* sysdeps/rs6000/ffs.c: Likewise.

1997-05-12 02:28  Ulrich Drepper  <drepper@cygnus.com>

	* time/sys/time.h: Make second argument of setitimer const.
	Patch by Michael Deutschmann <ldeutsch@mail.netshop.net>.
	* sysdeps/stub/setitimer.c: Likewise.
	* sysdeps/mach/hurd/setitimer.c: Likewise.
1997-05-21 01:48:59 +00:00

605 lines
14 KiB
C

/* Inline math functions for i387.
Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by John C. Bowman <bowman@ipp-garching.mpg.de>, 1995.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef __MATH_H
#define __MATH_H 1
#if defined __GNUG__ && \
(__GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ <= 7))
/* gcc 2.7.2 and 2.7.2.1 have problems with inlining `long double'
functions so we disable this now. */
#undef __NO_MATH_INLINES
#define __NO_MATH_INLINES
#endif
#ifdef __GNUC__
#ifndef __NO_MATH_INLINES
#ifdef __cplusplus
#define __MATH_INLINE __inline
#else
#define __MATH_INLINE extern __inline
#endif
__MATH_INLINE double cos (double);
__MATH_INLINE double sin (double);
__MATH_INLINE double __expm1 (double __x);
__MATH_INLINE double
__expm1 (double __x)
{
register double __value, __exponent, __temp;
__asm __volatile__
("fldl2e # e^x - 1 = 2^(x * log2(e)) - 1\n\t"
"fmul %%st(1) # x * log2(e)\n\t"
"fstl %%st(1)\n\t"
"frndint # int(x * log2(e))\n\t"
"fxch\n\t"
"fsub %%st(1) # fract(x * log2(e))\n\t"
"f2xm1 # 2^(fract(x * log2(e))) - 1\n\t"
"fscale # 2^(x * log2(e)) - 2^(int(x * log2(e)))\n\t"
: "=t" (__value), "=u" (__exponent) : "0" (__x));
__asm __volatile__
("fscale # 2^int(x * log2(e))\n\t"
: "=t" (__temp) : "0" (1.0), "u" (__exponent));
__temp -= 1.0;
return __temp + __value;
}
__MATH_INLINE double __sgn1 (double __x);
__MATH_INLINE double
__sgn1 (double __x)
{
return __x >= 0.0 ? 1.0 : -1.0;
}
__MATH_INLINE double sqrt (double __x);
__MATH_INLINE double
sqrt (double __x)
{
register double __value;
__asm __volatile__
("fsqrt"
: "=t" (__value) : "0" (__x));
return __value;
}
__MATH_INLINE double fabs (double __x);
__MATH_INLINE double
fabs (double __x)
{
register double __value;
__asm __volatile__
("fabs"
: "=t" (__value) : "0" (__x));
return __value;
}
/* The argument range of this inline version is limited. */
__MATH_INLINE double sin (double __x);
__MATH_INLINE double
sin (double __x)
{
register double __value;
__asm __volatile__
("fsin"
: "=t" (__value) : "0" (__x));
return __value;
}
/* The argument range of this inline version is limited. */
__MATH_INLINE double cos (double __x);
__MATH_INLINE double
cos (double __x)
{
register double __value;
__asm __volatile__
("fcos"
: "=t" (__value): "0" (__x));
return __value;
}
__MATH_INLINE double tan (double __x);
__MATH_INLINE double
tan (double __x)
{
register double __value;
register double __value2 __attribute__ ((unused));
__asm __volatile__
("fptan"
: "=t" (__value2), "=u" (__value) : "0" (__x));
return __value;
}
__MATH_INLINE double atan2 (double __y, double __x);
__MATH_INLINE double
atan2 (double __y, double __x)
{
register double __value;
__asm __volatile__
("fpatan\n\t"
"fldl %%st(0)"
: "=t" (__value) : "0" (__x), "u" (__y));
return __value;
}
__MATH_INLINE double asin (double __x);
__MATH_INLINE double
asin (double __x)
{
return atan2 (__x, sqrt (1.0 - __x * __x));
}
__MATH_INLINE double acos (double __x);
__MATH_INLINE double
acos (double __x)
{
return atan2 (sqrt (1.0 - __x * __x), __x);
}
__MATH_INLINE double atan (double __x);
__MATH_INLINE double
atan (double __x)
{
register double __value;
__asm __volatile__
("fld1\n\t"
"fpatan"
: "=t" (__value) : "0" (__x));
return __value;
}
__MATH_INLINE double exp (double __x);
__MATH_INLINE double
exp (double __x)
{
register double __value, __exponent;
__asm __volatile__
("fldl2e # e^x = 2^(x * log2(e))\n\t"
"fmul %%st(1) # x * log2(e)\n\t"
"fstl %%st(1)\n\t"
"frndint # int(x * log2(e))\n\t"
"fxch\n\t"
"fsub %%st(1) # fract(x * log2(e))\n\t"
"f2xm1 # 2^(fract(x * log2(e))) - 1\n\t"
: "=t" (__value), "=u" (__exponent) : "0" (__x));
__value += 1.0;
__asm __volatile__
("fscale"
: "=t" (__value) : "0" (__value), "u" (__exponent));
return __value;
}
__MATH_INLINE double sinh (double __x);
__MATH_INLINE double
sinh (double __x)
{
register double __exm1 = __expm1 (fabs (__x));
return 0.5 * (__exm1 / (__exm1 + 1.0) + __exm1) * __sgn1 (__x);
}
__MATH_INLINE double cosh (double __x);
__MATH_INLINE double
cosh (double __x)
{
register double __ex = exp (__x);
return 0.5 * (__ex + 1.0 / __ex);
}
__MATH_INLINE double tanh (double __x);
__MATH_INLINE double
tanh (double __x)
{
register double __exm1 = __expm1 (-fabs (__x + __x));
return __exm1 / (__exm1 + 2.0) * __sgn1 (-__x);
}
__MATH_INLINE double log (double __x);
__MATH_INLINE double
log (double __x)
{
register double __value;
__asm __volatile__
("fldln2\n\t"
"fxch\n\t"
"fyl2x"
: "=t" (__value) : "0" (__x));
return __value;
}
__MATH_INLINE double log10 (double __x);
__MATH_INLINE double
log10 (double __x)
{
register double __value;
__asm __volatile__
("fldlg2\n\t"
"fxch\n\t"
"fyl2x"
: "=t" (__value) : "0" (__x));
return __value;
}
__MATH_INLINE double __log2 (double __x);
__MATH_INLINE double
__log2 (double __x)
{
register double __value;
__asm __volatile__
("fld1\n\t"
"fxch\n\t"
"fyl2x"
: "=t" (__value) : "0" (__x));
return __value;
}
__MATH_INLINE double fmod (double __x, double __y);
__MATH_INLINE double
fmod (double __x, double __y)
{
register double __value;
__asm __volatile__
("1: fprem\n\t"
"fstsw %%ax\n\t"
"sahf\n\t"
"jp 1b"
: "=t" (__value) : "0" (__x), "u" (__y) : "ax", "cc");
return __value;
}
__MATH_INLINE double ldexp (double __x, int __y);
__MATH_INLINE double
ldexp (double __x, int __y)
{
register double __value;
__asm __volatile__
("fscale"
: "=t" (__value) : "0" (__x), "u" ((double) __y));
return __value;
}
__MATH_INLINE double pow (double __x, double __y);
__MATH_INLINE double
pow (double __x, double __y)
{
register double __value, __exponent;
long __p = (long) __y;
if (__x == 0.0 && __y > 0.0)
return 0.0;
if (__y == (double) __p)
{
double __r = 1.0;
if (__p == 0)
return 1.0;
if (__p < 0)
{
__p = -__p;
__x = 1.0 / __x;
}
while (1)
{
if (__p & 1)
__r *= __x;
__p >>= 1;
if (__p == 0)
return __r;
__x *= __x;
}
/* NOTREACHED */
}
__asm __volatile__
("fmul %%st(1) # y * log2(x)\n\t"
"fstl %%st(1)\n\t"
"frndint # int(y * log2(x))\n\t"
"fxch\n\t"
"fsub %%st(1) # fract(y * log2(x))\n\t"
"f2xm1 # 2^(fract(y * log2(x))) - 1\n\t"
: "=t" (__value), "=u" (__exponent) : "0" (__log2 (__x)), "1" (__y));
__value += 1.0;
__asm __volatile__
("fscale"
: "=t" (__value) : "0" (__value), "u" (__exponent));
return __value;
}
__MATH_INLINE double floor (double __x);
__MATH_INLINE double
floor (double __x)
{
register double __value;
__volatile unsigned short int __cw, __cwtmp;
__asm __volatile ("fnstcw %0" : "=m" (__cw));
__cwtmp = (__cw & 0xf3ff) | 0x0400; /* rounding down */
__asm __volatile ("fldcw %0" : : "m" (__cwtmp));
__asm __volatile ("frndint" : "=t" (__value) : "0" (__x));
__asm __volatile ("fldcw %0" : : "m" (__cw));
return __value;
}
__MATH_INLINE double ceil (double __x);
__MATH_INLINE double
ceil (double __x)
{
register double __value;
__volatile unsigned short int __cw, __cwtmp;
__asm __volatile ("fnstcw %0" : "=m" (__cw));
__cwtmp = (__cw & 0xf3ff) | 0x0800; /* rounding up */
__asm __volatile ("fldcw %0" : : "m" (__cwtmp));
__asm __volatile ("frndint" : "=t" (__value) : "0" (__x));
__asm __volatile ("fldcw %0" : : "m" (__cw));
return __value;
}
/* Optimized versions for some non-standardized functions. */
#if defined __USE_ISOC9X || defined __USE_MISC
__MATH_INLINE double hypot (double __x, double __y);
__MATH_INLINE double
hypot (double __x, double __y)
{
return sqrt (__x * __x + __y * __y);
}
__MATH_INLINE double log1p (double __x);
__MATH_INLINE double
log1p (double __x)
{
register double __value;
if (fabs (__x) >= 1.0 - 0.5 * M_SQRT2)
__value = log (1.0 + __x);
else
__asm __volatile__
("fldln2\n\t"
"fxch\n\t"
"fyl2xp1"
: "=t" (__value) : "0" (__x));
return __value;
}
__MATH_INLINE double asinh (double __x);
__MATH_INLINE double
asinh (double __x)
{
register double __y = fabs (__x);
return log1p ((__y * __y / (sqrt (__y * __y + 1.0) + 1.0) + __y)
* __sgn1 (__x));
}
__MATH_INLINE double acosh (double __x);
__MATH_INLINE double
acosh (double __x)
{
return log (__x + sqrt (__x - 1.0) * sqrt (__x + 1.0));
}
__MATH_INLINE double atanh (double __x);
__MATH_INLINE double
atanh (double __x)
{
register double __y = fabs (__x);
return -0.5 * __log1p (-(__y + __y) / (1.0 + __y)) * __sgn1 (__x);
}
__MATH_INLINE double logb (double __x);
__MATH_INLINE double
logb (double __x)
{
register double __value;
__asm __volatile__
("fxtract\n\t"
: "=t" (__value) : "0" (__x));
return __value;
}
__MATH_INLINE double drem (double __x, double __y);
__MATH_INLINE double
drem (double __x, double __y)
{
register double __value;
__asm __volatile__
("1: fprem1\n\t"
"fstsw %%ax\n\t"
"sahf\n\t"
"jp 1b"
: "=t" (__value) : "0" (__x), "u" (__y) : "ax", "cc");
return __value;
}
/* This function is used in the `isfinite' macro. */
__MATH_INLINE int __finite (double __x);
__MATH_INLINE int
__finite (double __x)
{
register int __result;
__asm__ __volatile__
("orl $0x800fffff, %0\n\t"
"incl %0\n\t"
"shrl $31, %0"
: "=q" (__result) : "0" (((int *) &__x)[1]));
return __result;
}
/* ISO C 9X defines some macros to perform unordered comparisons. The
ix87 FPU supports this with special opcodes and we should use them.
These must not be inline functions since we have to be able to handle
all floating-point types. */
#undef isgreater
#define isgreater(x, y) \
({ int result; \
__asm__ ("fucompp; fnstsw; andb $0x45, %%ah; setz %%al;" \
"andl $0xff, %0" \
: "=a" (result) : "t" (x), "u" (y) : "cc"); \
result; })
#undef isgreaterequal
#define isgreaterequal(x, y) \
({ int result; \
__asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al;" \
"andl $0xff, %0" \
: "=a" (result) : "t" (x), "u" (y) : "cc"); \
result; })
#undef isless
#define isless(x, y) \
({ int result; \
__asm__ ("fucompp; fnstsw; xorb $0x01, %%ah; testb $0x45, %%ah;" \
"setz %%al; andl $0xff, %0" \
: "=a" (result) : "t" (x), "u" (y) : "cc"); \
result; })
#undef islessequal
#define islessequal(x, y) \
({ int result; \
__asm__ ("fucompp; fnstsw; xorb $0x01, %%ah; testb $0x05, %%ah;" \
"setz %%al; andl $0xff, %0" \
: "=a" (result) : "t" (x), "u" (y) : "cc"); \
result; })
#undef islessgreater
#define islessgreater(x, y) \
({ int result; \
__asm__ ("fucompp; fnstsw; testb $0x44, %%ah; setz %%al;" \
"andl $0xff, %0" \
: "=a" (result) : "t" (x), "u" (y) : "cc"); \
result; })
#undef isunordered
#define isunordered(x, y) \
({ int result; \
__asm__ ("fucompp; fnstsw; sahf; setp %%al; andl $0xff, %0" \
: "=a" (result) : "t" (x), "u" (y) : "cc"); \
result; })
#endif
#ifdef __USE_MISC
__MATH_INLINE double coshm1 (double __x);
__MATH_INLINE double
coshm1 (double __x)
{
register double __exm1 = __expm1 (fabs (__x));
return 0.5 * (__exm1 / (__exm1 + 1.0)) * __exm1;
}
__MATH_INLINE double acosh1p (double __x);
__MATH_INLINE double
acosh1p (double __x)
{
return __log1p (__x + sqrt (__x) * sqrt (__x + 2.0));
}
__MATH_INLINE void sincos (double __x, double *__sinx, double *__cosx);
__MATH_INLINE void
sincos (double __x, double *__sinx, double *__cosx)
{
register double __cosr, __sinr;
__asm __volatile__
("fsincos\n\t"
"fnstsw %%ax\n\t"
"testl $0x400, %%eax\n\t"
"jz 1f\n\t"
"fldpi\n\t"
"fadd %%st(0)\n\t"
"fxch %%st(1)\n\t"
"2: fprem1\n\t"
"fnstsw %%ax\n\t"
"testl $0x400, %%eax\n\t"
"jnz 2b\n\t"
"fstp %%st(1)\n\t"
"fsincos\n\t"
"1:"
: "=t" (__cosr), "=u" (__sinr) : "0" (__x));
*__sinx = __sinr;
*__cosx = __cosr;
}
__MATH_INLINE double sgn (double __x);
__MATH_INLINE double
sgn (double __x)
{
return __x == 0.0 ? 0.0 : (__x > 0.0 ? 1.0 : -1.0);
}
__MATH_INLINE double pow2 (double __x);
__MATH_INLINE double
pow2 (double __x)
{
register double __value, __exponent;
long __p = (long) __x;
if (__x == (double) __p)
return ldexp (1.0, __p);
__asm __volatile__
("fldl %%st(0)\n\t"
"frndint # int(x)\n\t"
"fxch\n\t"
"fsub %%st(1) # fract(x)\n\t"
"f2xm1 # 2^(fract(x)) - 1\n\t"
: "=t" (__value), "=u" (__exponent) : "0" (__x));
__value += 1.0;
__asm __volatile__
("fscale"
: "=t" (__value) : "0" (__value), "u" (__exponent));
return __value;
}
#endif /* __USE_MISC */
#endif /* __NO_MATH_INLINES */
#endif /* __GNUC__ */
#endif /* __MATH_H */