/* Receive double x and two double results of cos(x) and return result which is more accurate, computing cos(x) with multi precision routine c32. */ double SECTION __cos32 (double x, double res, double res1) { int p; mp_no a, b, c; p = 32; __dbl_mp (res, &a, p); __dbl_mp (0.5 * (res1 - res), &b, p); __add (&a, &b, &c, p); if (x > 2.4) { __sub (&pi, &c, &a, p); __c32 (&a, &b, &c, p); b.d[0] = -b.d[0]; } else if (x > 0.8) { __sub (&hp, &c, &a, p); __c32 (&a, &c, &b, p); } else __c32 (&c, &b, &a, p); /* b=cos(0.5*(res+res1)) */ __dbl_mp (x, &c, p); /* c = x */ __sub (&b, &c, &a, p); /* if a > 0 return max (res, res1), otherwise return min (res, res1). */ if ((a.d[0] > 0 && res <= res1) || (a.d[0] <= 0 && res >= res1)) res = res1; LIBC_PROBE (slowacos, 2, &res, &x); return res; }
double SECTION __cos32(double x, double res, double res1) { int p; mp_no a,b,c; p=32; __dbl_mp(res,&a,p); __dbl_mp(0.5*(res1-res),&b,p); __add(&a,&b,&c,p); if (x>2.4) { __sub(&pi,&c,&a,p); __c32(&a,&b,&c,p); b.d[0]=-b.d[0]; } else if (x>0.8) { __sub(&hp,&c,&a,p); __c32(&a,&c,&b,p); } else __c32(&c,&b,&a,p); /* b=cos(0.5*(res+res1)) */ __dbl_mp(x,&c,p); /* c = x */ __sub(&b,&c,&a,p); /* if a>0 return max(res,res1), otherwise return min(res,res1) */ if (a.d[0]>0) return (res>res1)?res:res1; else return (res<res1)?res:res1; }
/* Compute cos() of double-length number (X + DX) as Multi Precision number and return result as double. If REDUCE_RANGE is true, X is assumed to be the original input and DX is ignored. */ double SECTION __mpcos (double x, double dx, bool reduce_range) { double y; mp_no a, b, c, s; int n; int p = 32; if (reduce_range) { n = __mpranred (x, &a, p); /* n is 0, 1, 2 or 3. */ __c32 (&a, &c, &s, p); } else { n = -1; __dbl_mp (x, &b, p); __dbl_mp (dx, &c, p); __add (&b, &c, &a, p); if (x > 0.8) { __sub (&hp, &a, &b, p); __c32 (&b, &s, &c, p); } else __c32 (&a, &c, &s, p); /* a = cos(x+dx) */ } /* Convert result based on which quarter of unit circle y is in. */ switch (n) { case 1: __mp_dbl (&s, &y, p); y = -y; break; case 3: __mp_dbl (&s, &y, p); break; case 2: __mp_dbl (&c, &y, p); y = -y; break; /* Quadrant not set, so the result must be cos (X + DX), which is also stored in C. */ case 0: default: __mp_dbl (&c, &y, p); } LIBC_PROBE (slowcos, 3, &x, &dx, &y); return y; }
double __mpsin(double x, double dx) { int p; double y; mp_no a,b,c; p=32; __dbl_mp(x,&a,p); __dbl_mp(dx,&b,p); __add(&a,&b,&c,p); if (x>0.8) { __sub(&hp,&c,&a,p); __c32(&a,&b,&c,p); } else __c32(&c,&a,&b,p); /* b = sin(x+dx) */ __mp_dbl(&b,&y,p); return y; }
double SECTION __mpsin1(double x) { int p; int n; mp_no u,s,c; double y; p=32; n=__mpranred(x,&u,p); /* n is 0, 1, 2 or 3 */ __c32(&u,&c,&s,p); switch (n) { /* in which quarter of unit circle y is*/ case 0: __mp_dbl(&s,&y,p); return y; break; case 2: __mp_dbl(&s,&y,p); return -y; break; case 1: __mp_dbl(&c,&y,p); return y; break; case 3: __mp_dbl(&c,&y,p); return -y; break; } return 0; /* unreachable, to make the compiler happy */ }
void SECTION __mptan (double x, mp_no *mpy, int p) { int n; mp_no mpw, mpc, mps; /* Negative or positive result. */ n = __mpranred (x, &mpw, p) & 0x00000001; /* Computing sin(x) and cos(x). */ __c32 (&mpw, &mpc, &mps, p); /* Second or fourth quarter of unit circle. */ if (n) { __dvd (&mpc, &mps, mpy, p); mpy->d[0] *= -1; } /* tan is negative in this area. */ else __dvd (&mps, &mpc, mpy, p); }