/******************************************************************\ * * * last modified: 23 May 1992. * * * * Copyright (C) 1989 by Matthew Self. * * You may freely distribute verbatim copies of this software * * provided that this copyright notice is retained in all copies. * * You may distribute modifications to this software under the * * conditions above if you also clearly note such modifications * * with their author and date. * * * * Note: errno is not set to EDOM when domain errors occur for * * most of these functions. Rather, it is assumed that the * * 68881's OPERR exception will be enabled and handled * * appropriately by the operating system. Similarly, overflow * * and underflow do not set errno to ERANGE. * * * * Send bugs to Matthew Self (self@bayes.arc.nasa.gov). * * * \******************************************************************/ /* This file is NOT a part of GCC, just distributed with it. */ /* If you find this in GCC, please send bug reports to bug-gcc@prep.ai.mit.edu. */ /* Changed by Richard Stallman: May 1993, add conditional to prevent multiple inclusion. % inserted before a #. New function `hypot' added. Nans written in hex to avoid 0rnan. May 1992, use %! for fpcr register. Break lines before function names. December 1989, add parens around `&' in pow. November 1990, added alternate definition of HUGE_VAL for Sun. */ /* Changed by Jim Wilson: September 1993, Use #undef before HUGE_VAL instead of #ifdef/#endif. */ /* Changed by Ian Lance Taylor: September 1994, use extern inline instead of static inline. */ #ifndef __math_68881 #define __math_68881 #include #undef HUGE_VAL #ifdef __sun__ /* The Sun assembler fails to handle the hex constant in the usual defn. */ #define HUGE_VAL \ ({ \ static union { int i[2]; double d; } u = { {0x7ff00000, 0} }; \ u.d; \ }) #else #define HUGE_VAL \ ({ \ double huge_val; \ \ __asm ("fmove%.d #0x7ff0000000000000,%0" /* Infinity */ \ : "=f" (huge_val) \ : /* no inputs */); \ huge_val; \ }) #endif __inline extern double sin (double x) { double value; __asm ("fsin%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double cos (double x) { double value; __asm ("fcos%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double tan (double x) { double value; __asm ("ftan%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double asin (double x) { double value; __asm ("fasin%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double acos (double x) { double value; __asm ("facos%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double atan (double x) { double value; __asm ("fatan%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double atan2 (double y, double x) { double pi, pi_over_2; __asm ("fmovecr%.x #0,%0" /* extended precision pi */ : "=f" (pi) : /* no inputs */ ); __asm ("fscale%.b #-1,%0" /* no loss of accuracy */ : "=f" (pi_over_2) : "0" (pi)); if (x > 0) { if (y > 0) { if (x > y) return atan (y / x); else return pi_over_2 - atan (x / y); } else { if (x > -y) return atan (y / x); else return - pi_over_2 - atan (x / y); } } else { if (y < 0) { if (-x > -y) return - pi + atan (y / x); else return - pi_over_2 - atan (x / y); } else { if (-x > y) return pi + atan (y / x); else if (y > 0) return pi_over_2 - atan (x / y); else { double value; errno = EDOM; __asm ("fmove%.d #0x7fffffffffffffff,%0" /* quiet NaN */ : "=f" (value) : /* no inputs */); return value; } } } } __inline extern double sinh (double x) { double value; __asm ("fsinh%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double cosh (double x) { double value; __asm ("fcosh%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double tanh (double x) { double value; __asm ("ftanh%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double atanh (double x) { double value; __asm ("fatanh%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double exp (double x) { double value; __asm ("fetox%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double expm1 (double x) { double value; __asm ("fetoxm1%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double log (double x) { double value; __asm ("flogn%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double log1p (double x) { double value; __asm ("flognp1%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double log10 (double x) { double value; __asm ("flog10%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double sqrt (double x) { double value; __asm ("fsqrt%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double hypot (double x, double y) { return sqrt (x*x + y*y); } __inline extern double pow (double x, double y) { if (x > 0) return exp (y * log (x)); else if (x == 0) { if (y > 0) return 0.0; else { double value; errno = EDOM; __asm ("fmove%.d #0x7fffffffffffffff,%0" /* quiet NaN */ : "=f" (value) : /* no inputs */); return value; } } else { double temp; __asm ("fintrz%.x %1,%0" : "=f" (temp) /* integer-valued float */ : "f" (y)); if (y == temp) { int i = (int) y; if ((i & 1) == 0) /* even */ return exp (y * log (-x)); else return - exp (y * log (-x)); } else { double value; errno = EDOM; __asm ("fmove%.d #0x7fffffffffffffff,%0" /* quiet NaN */ : "=f" (value) : /* no inputs */); return value; } } } __inline extern double fabs (double x) { double value; __asm ("fabs%.x %1,%0" : "=f" (value) : "f" (x)); return value; } __inline extern double ceil (double x) { int rounding_mode, round_up; double value; __asm volatile ("fmove%.l %!,%0" : "=dm" (rounding_mode) : /* no inputs */ ); round_up = rounding_mode | 0x30; __asm volatile ("fmove%.l %0,%!" : /* no outputs */ : "dmi" (round_up)); __asm volatile ("fint%.x %1,%0" : "=f" (value) : "f" (x)); __asm volatile ("fmove%.l %0,%!" : /* no outputs */ : "dmi" (rounding_mode)); return value; } __inline extern double floor (double x) { int rounding_mode, round_down; double value; __asm volatile ("fmove%.l %!,%0" : "=dm" (rounding_mode) : /* no inputs */ ); round_down = (rounding_mode & ~0x10) | 0x20; __asm volatile ("fmove%.l %0,%!" : /* no outputs */ : "dmi" (round_down)); __asm volatile ("fint%.x %1,%0" : "=f" (value) : "f" (x)); __asm volatile ("fmove%.l %0,%!" : /* no outputs */ : "dmi" (rounding_mode)); return value; } __inline extern double rint (double x) { int rounding_mode, round_nearest; double value; __asm volatile ("fmove%.l %!,%0" : "=dm" (rounding_mode) : /* no inputs */ ); round_nearest = rounding_mode & ~0x30; __asm volatile ("fmove%.l %0,%!" : /* no outputs */ : "dmi" (round_nearest)); __asm volatile ("fint%.x %1,%0" : "=f" (value) : "f" (x)); __asm volatile ("fmove%.l %0,%!" : /* no outputs */ : "dmi" (rounding_mode)); return value; } __inline extern double fmod (double x, double y) { double value; __asm ("fmod%.x %2,%0" : "=f" (value) : "0" (x), "f" (y)); return value; } __inline extern double drem (double x, double y) { double value; __asm ("frem%.x %2,%0" : "=f" (value) : "0" (x), "f" (y)); return value; } __inline extern double scalb (double x, int n) { double value; __asm ("fscale%.l %2,%0" : "=f" (value) : "0" (x), "dmi" (n)); return value; } __inline extern double logb (double x) { double exponent; __asm ("fgetexp%.x %1,%0" : "=f" (exponent) : "f" (x)); return exponent; } __inline extern double ldexp (double x, int n) { double value; __asm ("fscale%.l %2,%0" : "=f" (value) : "0" (x), "dmi" (n)); return value; } __inline extern double frexp (double x, int *exp) { double float_exponent; int int_exponent; double mantissa; __asm ("fgetexp%.x %1,%0" : "=f" (float_exponent) /* integer-valued float */ : "f" (x)); int_exponent = (int) float_exponent; __asm ("fgetman%.x %1,%0" : "=f" (mantissa) /* 1.0 <= mantissa < 2.0 */ : "f" (x)); if (mantissa != 0) { __asm ("fscale%.b #-1,%0" : "=f" (mantissa) /* mantissa /= 2.0 */ : "0" (mantissa)); int_exponent += 1; } *exp = int_exponent; return mantissa; } __inline extern double modf (double x, double *ip) { double temp; __asm ("fintrz%.x %1,%0" : "=f" (temp) /* integer-valued float */ : "f" (x)); *ip = temp; return x - temp; } #endif /* not __math_68881 */