Back to index

glibc  2.9
sincos32.c
Go to the documentation of this file.
00001 /*
00002  * IBM Accurate Mathematical Library
00003  * written by International Business Machines Corp.
00004  * Copyright (C) 2001 Free Software Foundation
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2.1 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019  */
00020 /****************************************************************/
00021 /*  MODULE_NAME: sincos32.c                                     */
00022 /*                                                              */
00023 /*  FUNCTIONS: ss32                                             */
00024 /*             cc32                                             */
00025 /*             c32                                              */
00026 /*             sin32                                            */
00027 /*             cos32                                            */
00028 /*             mpsin                                            */
00029 /*             mpcos                                            */
00030 /*             mpranred                                         */
00031 /*             mpsin1                                           */
00032 /*             mpcos1                                           */
00033 /*                                                              */
00034 /* FILES NEEDED: endian.h mpa.h sincos32.h                      */
00035 /*               mpa.c                                          */
00036 /*                                                              */
00037 /* Multi Precision sin() and cos() function with p=32  for sin()*/
00038 /* cos() arcsin() and arccos() routines                         */
00039 /* In addition mpranred() routine  performs range  reduction of */
00040 /* a double number x into multi precision number   y,           */
00041 /* such that y=x-n*pi/2, abs(y)<pi/4,  n=0,+-1,+-2,....         */
00042 /****************************************************************/
00043 #include "endian.h"
00044 #include "mpa.h"
00045 #include "sincos32.h"
00046 #include "math_private.h"
00047 
00048 /****************************************************************/
00049 /* Compute Multi-Precision sin() function for given p.  Receive */
00050 /* Multi  Precision number x and result stored at y             */
00051 /****************************************************************/
00052 static void ss32(mp_no *x, mp_no *y, int p) {
00053   int i;
00054   double a;
00055 #if 0
00056   double b;
00057   static const mp_no mpone = {1,{1.0,1.0}};
00058 #endif
00059   mp_no mpt1,x2,gor,sum ,mpk={1,{1.0}};
00060 #if 0
00061   mp_no mpt2;
00062 #endif
00063   for (i=1;i<=p;i++) mpk.d[i]=0;
00064 
00065   __mul(x,x,&x2,p);
00066   __cpy(&oofac27,&gor,p);
00067   __cpy(&gor,&sum,p);
00068   for (a=27.0;a>1.0;a-=2.0) {
00069     mpk.d[1]=a*(a-1.0);
00070     __mul(&gor,&mpk,&mpt1,p);
00071     __cpy(&mpt1,&gor,p);
00072     __mul(&x2,&sum,&mpt1,p);
00073     __sub(&gor,&mpt1,&sum,p);
00074   }
00075   __mul(x,&sum,y,p);
00076 }
00077 
00078 /**********************************************************************/
00079 /* Compute Multi-Precision cos() function for given p. Receive Multi  */
00080 /* Precision number x and result stored at y                          */
00081 /**********************************************************************/
00082 static void cc32(mp_no *x, mp_no *y, int p) {
00083   int i;
00084   double a;
00085 #if 0
00086   double b;
00087   static const mp_no mpone = {1,{1.0,1.0}};
00088 #endif
00089   mp_no mpt1,x2,gor,sum ,mpk={1,{1.0}};
00090 #if 0
00091   mp_no mpt2;
00092 #endif
00093   for (i=1;i<=p;i++) mpk.d[i]=0;
00094 
00095   __mul(x,x,&x2,p);
00096   mpk.d[1]=27.0;
00097   __mul(&oofac27,&mpk,&gor,p);
00098   __cpy(&gor,&sum,p);
00099   for (a=26.0;a>2.0;a-=2.0) {
00100     mpk.d[1]=a*(a-1.0);
00101     __mul(&gor,&mpk,&mpt1,p);
00102     __cpy(&mpt1,&gor,p);
00103     __mul(&x2,&sum,&mpt1,p);
00104     __sub(&gor,&mpt1,&sum,p);
00105   }
00106   __mul(&x2,&sum,y,p);
00107 }
00108 
00109 /***************************************************************************/
00110 /* c32()   computes both sin(x), cos(x) as Multi precision numbers         */
00111 /***************************************************************************/
00112 void __c32(mp_no *x, mp_no *y, mp_no *z, int p) {
00113   static const mp_no mpt={1,{1.0,2.0}}, one={1,{1.0,1.0}};
00114   mp_no u,t,t1,t2,c,s;
00115   int i;
00116   __cpy(x,&u,p);
00117   u.e=u.e-1;
00118   cc32(&u,&c,p);
00119   ss32(&u,&s,p);
00120   for (i=0;i<24;i++) {
00121     __mul(&c,&s,&t,p);
00122     __sub(&s,&t,&t1,p);
00123     __add(&t1,&t1,&s,p);
00124     __sub(&mpt,&c,&t1,p);
00125     __mul(&t1,&c,&t2,p);
00126     __add(&t2,&t2,&c,p);
00127   }
00128   __sub(&one,&c,y,p);
00129   __cpy(&s,z,p);
00130 }
00131 
00132 /************************************************************************/
00133 /*Routine receive double x and two double results of sin(x) and return  */
00134 /*result which is more accurate                                         */
00135 /*Computing sin(x) with multi precision routine c32                     */
00136 /************************************************************************/
00137 double __sin32(double x, double res, double res1) {
00138   int p;
00139   mp_no a,b,c;
00140   p=32;
00141   __dbl_mp(res,&a,p);
00142   __dbl_mp(0.5*(res1-res),&b,p);
00143   __add(&a,&b,&c,p);
00144   if (x>0.8)
00145   { __sub(&hp,&c,&a,p);
00146     __c32(&a,&b,&c,p);
00147   }
00148   else __c32(&c,&a,&b,p);     /* b=sin(0.5*(res+res1))  */
00149   __dbl_mp(x,&c,p);           /* c = x                  */
00150   __sub(&b,&c,&a,p);
00151   /* if a>0 return min(res,res1), otherwise return max(res,res1) */
00152   if (a.d[0]>0)  return (res<res1)?res:res1;
00153   else  return (res>res1)?res:res1;
00154 }
00155 
00156 /************************************************************************/
00157 /*Routine receive double x and two double results of cos(x) and return  */
00158 /*result which is more accurate                                         */
00159 /*Computing cos(x) with multi precision routine c32                     */
00160 /************************************************************************/
00161 double __cos32(double x, double res, double res1) {
00162   int p;
00163   mp_no a,b,c;
00164   p=32;
00165   __dbl_mp(res,&a,p);
00166   __dbl_mp(0.5*(res1-res),&b,p);
00167   __add(&a,&b,&c,p);
00168   if (x>2.4)
00169   { __sub(&pi,&c,&a,p);
00170     __c32(&a,&b,&c,p);
00171     b.d[0]=-b.d[0];
00172   }
00173   else if (x>0.8)
00174        { __sub(&hp,&c,&a,p);
00175          __c32(&a,&c,&b,p);
00176        }
00177   else __c32(&c,&b,&a,p);     /* b=cos(0.5*(res+res1))  */
00178   __dbl_mp(x,&c,p);    /* c = x                  */
00179   __sub(&b,&c,&a,p);
00180              /* if a>0 return max(res,res1), otherwise return min(res,res1) */
00181   if (a.d[0]>0)  return (res>res1)?res:res1;
00182   else  return (res<res1)?res:res1;
00183 }
00184 
00185 /*******************************************************************/
00186 /*Compute sin(x+dx) as Multi Precision number and return result as */
00187 /* double                                                          */
00188 /*******************************************************************/
00189 double __mpsin(double x, double dx) {
00190   int p;
00191   double y;
00192   mp_no a,b,c;
00193   p=32;
00194   __dbl_mp(x,&a,p);
00195   __dbl_mp(dx,&b,p);
00196   __add(&a,&b,&c,p);
00197   if (x>0.8) { __sub(&hp,&c,&a,p); __c32(&a,&b,&c,p); }
00198   else __c32(&c,&a,&b,p);     /* b = sin(x+dx)     */
00199   __mp_dbl(&b,&y,p);
00200   return y;
00201 }
00202 
00203 /*******************************************************************/
00204 /* Compute cos()of double-length number (x+dx) as Multi Precision  */
00205 /* number and return result as double                              */
00206 /*******************************************************************/
00207 double __mpcos(double x, double dx) {
00208   int p;
00209   double y;
00210   mp_no a,b,c;
00211   p=32;
00212   __dbl_mp(x,&a,p);
00213   __dbl_mp(dx,&b,p);
00214   __add(&a,&b,&c,p);
00215   if (x>0.8)
00216   { __sub(&hp,&c,&b,p);
00217     __c32(&b,&c,&a,p);
00218   }
00219   else __c32(&c,&a,&b,p);     /* a = cos(x+dx)     */
00220   __mp_dbl(&a,&y,p);
00221   return y;
00222 }
00223 
00224 /******************************************************************/
00225 /* mpranred() performs range reduction of a double number x into  */
00226 /* multi precision number y, such that y=x-n*pi/2, abs(y)<pi/4,   */
00227 /* n=0,+-1,+-2,....                                               */
00228 /* Return int which indicates in which quarter of circle x is     */
00229 /******************************************************************/
00230 int __mpranred(double x, mp_no *y, int p)
00231 {
00232   number v;
00233   double t,xn;
00234   int i,k,n;
00235   static const mp_no one = {1,{1.0,1.0}};
00236   mp_no a,b,c;
00237 
00238   if (ABS(x) < 2.8e14) {
00239     t = (x*hpinv.d + toint.d);
00240     xn = t - toint.d;
00241     v.d = t;
00242     n =v.i[LOW_HALF]&3;
00243     __dbl_mp(xn,&a,p);
00244     __mul(&a,&hp,&b,p);
00245     __dbl_mp(x,&c,p);
00246     __sub(&c,&b,y,p);
00247     return n;
00248   }
00249   else {                      /* if x is very big more precision required */
00250     __dbl_mp(x,&a,p);
00251     a.d[0]=1.0;
00252     k = a.e-5;
00253     if (k < 0) k=0;
00254     b.e = -k;
00255     b.d[0] = 1.0;
00256     for (i=0;i<p;i++) b.d[i+1] = toverp[i+k];
00257     __mul(&a,&b,&c,p);
00258     t = c.d[c.e];
00259     for (i=1;i<=p-c.e;i++) c.d[i]=c.d[i+c.e];
00260     for (i=p+1-c.e;i<=p;i++) c.d[i]=0;
00261     c.e=0;
00262     if (c.d[1] >=  8388608.0)
00263     { t +=1.0;
00264       __sub(&c,&one,&b,p);
00265       __mul(&b,&hp,y,p);
00266     }
00267     else __mul(&c,&hp,y,p);
00268     n = (int) t;
00269     if (x < 0) { y->d[0] = - y->d[0]; n = -n; }
00270     return (n&3);
00271   }
00272 }
00273 
00274 /*******************************************************************/
00275 /* Multi-Precision sin() function subroutine, for p=32.  It is     */
00276 /* based on the routines mpranred() and c32().                     */
00277 /*******************************************************************/
00278 double __mpsin1(double x)
00279 {
00280   int p;
00281   int n;
00282   mp_no u,s,c;
00283   double y;
00284   p=32;
00285   n=__mpranred(x,&u,p);               /* n is 0, 1, 2 or 3 */
00286   __c32(&u,&c,&s,p);
00287   switch (n) {                      /* in which quarter of unit circle y is*/
00288   case 0:
00289     __mp_dbl(&s,&y,p);
00290     return y;
00291     break;
00292 
00293   case 2:
00294     __mp_dbl(&s,&y,p);
00295     return -y;
00296     break;
00297 
00298   case 1:
00299     __mp_dbl(&c,&y,p);
00300     return y;
00301     break;
00302 
00303   case 3:
00304     __mp_dbl(&c,&y,p);
00305     return -y;
00306     break;
00307 
00308   }
00309   return 0;                     /* unreachable, to make the compiler happy */
00310 }
00311 
00312 /*****************************************************************/
00313 /* Multi-Precision cos() function subroutine, for p=32.  It is   */
00314 /* based  on the routines mpranred() and c32().                  */
00315 /*****************************************************************/
00316 
00317 double __mpcos1(double x)
00318 {
00319   int p;
00320   int n;
00321   mp_no u,s,c;
00322   double y;
00323 
00324   p=32;
00325   n=__mpranred(x,&u,p);              /* n is 0, 1, 2 or 3 */
00326   __c32(&u,&c,&s,p);
00327   switch (n) {                     /* in what quarter of unit circle y is*/
00328 
00329   case 0:
00330     __mp_dbl(&c,&y,p);
00331     return y;
00332     break;
00333 
00334   case 2:
00335     __mp_dbl(&c,&y,p);
00336     return -y;
00337     break;
00338 
00339   case 1:
00340     __mp_dbl(&s,&y,p);
00341     return -y;
00342     break;
00343 
00344   case 3:
00345     __mp_dbl(&s,&y,p);
00346     return y;
00347     break;
00348 
00349   }
00350   return 0;                     /* unreachable, to make the compiler happy */
00351 }
00352 /******************************************************************/