📄 s_sin.cpp
字号:
/* See the import.pl script for potential modifications */
/*
* IBM Accurate Mathematical Library
* written by International Business Machines Corp.
* Copyright (C) 2001 Free Software Foundation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/****************************************************************************/
/* */
/* MODULE_NAME:usncs.c */
/* */
/* FUNCTIONS: usin */
/* ucos */
/* slow */
/* slow1 */
/* slow2 */
/* sloww */
/* sloww1 */
/* sloww2 */
/* bsloww */
/* bsloww1 */
/* bsloww2 */
/* cslow2 */
/* csloww */
/* csloww1 */
/* csloww2 */
/* FILES NEEDED: dla.h endian.h mpa.h mydefs.h usncs.h */
/* branred.c sincos32.c dosincos.c mpa.c */
/* sincos.tbl */
/* */
/* An ultimate sin and routine. Given an IEEE Double machine number x */
/* it computes the correctly rounded (to nearest) value of sin(x) or cos(x) */
/* Assumption: Machine arithmetic operations are performed in */
/* round to nearest mode of IEEE 754 standard. */
/* */
/****************************************************************************/
#include "endian.h"
#include "mydefs.h"
#include "usncs.h"
#include "MathLib.h"
#include "sincos.tbl"
#include "math_private.h"
static const Double
sn3 = -1.66666666666664880952546298448555E-01,
sn5 = 8.33333214285722277379541354343671E-03,
cs2 = 4.99999999999999999999950396842453E-01,
cs4 = -4.16666666666664434524222570944589E-02,
cs6 = 1.38888874007937613028114285595617E-03;
void __dubsin(Double x, Double dx, Double w[]);
void __docos(Double x, Double dx, Double w[]);
Double __mpsin(Double x, Double dx);
Double __mpcos(Double x, Double dx);
Double __mpsin1(Double x);
Double __mpcos1(Double x);
namespace streflop_libm {
static Double slow(Double x);
static Double slow1(Double x);
static Double slow2(Double x);
static Double sloww(Double x, Double dx, Double orig);
static Double sloww1(Double x, Double dx, Double orig);
static Double sloww2(Double x, Double dx, Double orig, int n);
static Double bsloww(Double x, Double dx, Double orig, int n);
static Double bsloww1(Double x, Double dx, Double orig, int n);
static Double bsloww2(Double x, Double dx, Double orig, int n);
int __branred(Double x, Double *a, Double *aa);
static Double cslow2(Double x);
static Double csloww(Double x, Double dx, Double orig);
static Double csloww1(Double x, Double dx, Double orig);
static Double csloww2(Double x, Double dx, Double orig, int n);
/*******************************************************************/
/* An ultimate sin routine. Given an IEEE Double machine number x */
/* it computes the correctly rounded (to nearest) value of sin(x) */
/*******************************************************************/
Double __sin(Double x){
Double xx,res,t,cor,y,s,c,sn,ssn,cs,ccs,xn,a,da,db,eps,xn1,xn2;
#if 0
Double w[2];
#endif
mynumber u,v;
int4 k,m,n;
#if 0
int4 nn;
#endif
u.x() = x;
m = u.i[HIGH_HALF];
k = 0x7fffffff&m; /* no sign */
if (k < 0x3e500000) /* if x->0 =>sin(x)=x */
return x;
/*---------------------------- 2^-26 < |x|< 0.25 ----------------------*/
else if (k < 0x3fd00000){
xx = x*x;
/*Taylor series */
t = ((((s5.x()*xx + s4.x())*xx + s3.x())*xx + s2.x())*xx + s1.x())*(xx*x);
res = x+t;
cor = (x-res)+t;
return (res == res + 1.07*cor)? res : slow(x);
} /* else if (k < 0x3fd00000) */
/*---------------------------- 0.25<|x|< 0.855469---------------------- */
else if (k < 0x3feb6000) {
u.x()=(m>0)?big.x()+x:big.x()-x;
y=(m>0)?x-(u.x()-big.x()):x+(u.x()-big.x());
xx=y*y;
s = y + y*xx*(sn3 +xx*sn5);
c = xx*(cs2 +xx*(cs4 + xx*cs6));
k=u.i[LOW_HALF]<<2;
sn=(m>0)?sincos.x(k):-sincos.x(k);
ssn=(m>0)?sincos.x(k+1):-sincos.x(k+1);
cs=sincos.x(k+2);
ccs=sincos.x(k+3);
cor=(ssn+s*ccs-sn*c)+cs*s;
res=sn+cor;
cor=(sn-res)+cor;
return (res==res+1.025*cor)? res : slow1(x);
} /* else if (k < 0x3feb6000) */
/*----------------------- 0.855469 <|x|<2.426265 ----------------------*/
else if (k < 0x400368fd ) {
y = (m>0)? hp0.x()-x:hp0.x()+x;
if (y>=0) {
u.x() = big.x()+y;
y = (y-(u.x()-big.x()))+hp1.x();
}
else {
u.x() = big.x()-y;
y = (-hp1.x()) - (y+(u.x()-big.x()));
}
xx=y*y;
s = y + y*xx*(sn3 +xx*sn5);
c = xx*(cs2 +xx*(cs4 + xx*cs6));
k=u.i[LOW_HALF]<<2;
sn=sincos.x(k);
ssn=sincos.x(k+1);
cs=sincos.x(k+2);
ccs=sincos.x(k+3);
cor=(ccs-s*ssn-cs*c)-sn*s;
res=cs+cor;
cor=(cs-res)+cor;
return (res==res+1.020*cor)? ((m>0)?res:-res) : slow2(x);
} /* else if (k < 0x400368fd) */
/*-------------------------- 2.426265<|x|< 105414350 ----------------------*/
else if (k < 0x419921FB ) {
t = (x*hpinv.x() + toint.x());
xn = t - toint.x();
v.x() = t;
y = (x - xn*mp1.x()) - xn*mp2.x();
n =v.i[LOW_HALF]&3;
da = xn*mp3.x();
a=y-da;
da = (y-a)-da;
eps = ABS(x)*1.2e-30;
switch (n) { /* quarter of unit circle */
case 0:
case 2:
xx = a*a;
if (n) {a=-a;da=-da;}
if (xx < 0.01588) {
/*Taylor series */
t = (((((s5.x()*xx + s4.x())*xx + s3.x())*xx + s2.x())*xx + s1.x())*a - 0.5*da)*xx+da;
res = a+t;
cor = (a-res)+t;
cor = (cor>0)? 1.02*cor+eps : 1.02*cor -eps;
return (res == res + cor)? res : sloww(a,da,x);
}
else {
if (a>0)
{m=1;t=a;db=da;}
else
{m=0;t=-a;db=-da;}
u.x()=big.x()+t;
y=t-(u.x()-big.x());
xx=y*y;
s = y + (db+y*xx*(sn3 +xx*sn5));
c = y*db+xx*(cs2 +xx*(cs4 + xx*cs6));
k=u.i[LOW_HALF]<<2;
sn=sincos.x(k);
ssn=sincos.x(k+1);
cs=sincos.x(k+2);
ccs=sincos.x(k+3);
cor=(ssn+s*ccs-sn*c)+cs*s;
res=sn+cor;
cor=(sn-res)+cor;
cor = (cor>0)? 1.035*cor+eps : 1.035*cor-eps;
return (res==res+cor)? ((m)?res:-res) : sloww1(a,da,x);
}
break;
case 1:
case 3:
if (a<0)
{a=-a;da=-da;}
u.x()=big.x()+a;
y=a-(u.x()-big.x())+da;
xx=y*y;
k=u.i[LOW_HALF]<<2;
sn=sincos.x(k);
ssn=sincos.x(k+1);
cs=sincos.x(k+2);
ccs=sincos.x(k+3);
s = y + y*xx*(sn3 +xx*sn5);
c = xx*(cs2 +xx*(cs4 + xx*cs6));
cor=(ccs-s*ssn-cs*c)-sn*s;
res=cs+cor;
cor=(cs-res)+cor;
cor = (cor>0)? 1.025*cor+eps : 1.025*cor-eps;
return (res==res+cor)? ((n&2)?-res:res) : sloww2(a,da,x,n);
break;
}
} /* else if (k < 0x419921FB ) */
/*---------------------105414350 <|x|< 281474976710656 --------------------*/
else if (k < 0x42F00000 ) {
t = (x*hpinv.x() + toint.x());
xn = t - toint.x();
v.x() = t;
xn1 = (xn+8.0e22)-8.0e22;
xn2 = xn - xn1;
y = ((((x - xn1*mp1.x()) - xn1*mp2.x())-xn2*mp1.x())-xn2*mp2.x());
n =v.i[LOW_HALF]&3;
da = xn1*pp3.x();
t=y-da;
da = (y-t)-da;
da = (da - xn2*pp3.x()) -xn*pp4.x();
a = t+da;
da = (t-a)+da;
eps = 1.0e-24;
switch (n) {
case 0:
case 2:
xx = a*a;
if (n) {a=-a;da=-da;}
if (xx < 0.01588) {
/* Taylor series */
t = (((((s5.x()*xx + s4.x())*xx + s3.x())*xx + s2.x())*xx + s1.x())*a - 0.5*da)*xx+da;
res = a+t;
cor = (a-res)+t;
cor = (cor>0)? 1.02*cor+eps : 1.02*cor -eps;
return (res == res + cor)? res : bsloww(a,da,x,n);
}
else {
if (a>0) {m=1;t=a;db=da;}
else {m=0;t=-a;db=-da;}
u.x()=big.x()+t;
y=t-(u.x()-big.x());
xx=y*y;
s = y + (db+y*xx*(sn3 +xx*sn5));
c = y*db+xx*(cs2 +xx*(cs4 + xx*cs6));
k=u.i[LOW_HALF]<<2;
sn=sincos.x(k);
ssn=sincos.x(k+1);
cs=sincos.x(k+2);
ccs=sincos.x(k+3);
cor=(ssn+s*ccs-sn*c)+cs*s;
res=sn+cor;
cor=(sn-res)+cor;
cor = (cor>0)? 1.035*cor+eps : 1.035*cor-eps;
return (res==res+cor)? ((m)?res:-res) : bsloww1(a,da,x,n);
}
break;
case 1:
case 3:
if (a<0)
{a=-a;da=-da;}
u.x()=big.x()+a;
y=a-(u.x()-big.x())+da;
xx=y*y;
k=u.i[LOW_HALF]<<2;
sn=sincos.x(k);
ssn=sincos.x(k+1);
cs=sincos.x(k+2);
ccs=sincos.x(k+3);
s = y + y*xx*(sn3 +xx*sn5);
c = xx*(cs2 +xx*(cs4 + xx*cs6));
cor=(ccs-s*ssn-cs*c)-sn*s;
res=cs+cor;
cor=(cs-res)+cor;
cor = (cor>0)? 1.025*cor+eps : 1.025*cor-eps;
return (res==res+cor)? ((n&2)?-res:res) : bsloww2(a,da,x,n);
break;
}
} /* else if (k < 0x42F00000 ) */
/* -----------------281474976710656 <|x| <2^1024----------------------------*/
else if (k < 0x7ff00000) {
n = __branred(x,&a,&da);
switch (n) {
case 0:
if (a*a < 0.01588) return bsloww(a,da,x,n);
else return bsloww1(a,da,x,n);
break;
case 2:
if (a*a < 0.01588) return bsloww(-a,-da,x,n);
else return bsloww1(-a,-da,x,n);
break;
case 1:
case 3:
return bsloww2(a,da,x,n);
break;
}
} /* else if (k < 0x7ff00000 ) */
/*--------------------- |x| > 2^1024 ----------------------------------*/
else return x / x;
return 0; /* unreachable */
}
/*******************************************************************/
/* An ultimate cos routine. Given an IEEE Double machine number x */
/* it computes the correctly rounded (to nearest) value of cos(x) */
/*******************************************************************/
Double __cos(Double x)
{
Double y,xx,res,t,cor,s,c,sn,ssn,cs,ccs,xn,a,da,db,eps,xn1,xn2;
mynumber u,v;
int4 k,m,n;
u.x() = x;
m = u.i[HIGH_HALF];
k = 0x7fffffff&m;
if (k < 0x3e400000 ) return 1.0; /* |x|<2^-27 => cos(x)=1 */
else if (k < 0x3feb6000 ) {/* 2^-27 < |x| < 0.855469 */
y=ABS(x);
u.x() = big.x()+y;
y = y-(u.x()-big.x());
xx=y*y;
s = y + y*xx*(sn3 +xx*sn5);
c = xx*(cs2 +xx*(cs4 + xx*cs6));
k=u.i[LOW_HALF]<<2;
sn=sincos.x(k);
ssn=sincos.x(k+1);
cs=sincos.x(k+2);
ccs=sincos.x(k+3);
cor=(ccs-s*ssn-cs*c)-sn*s;
res=cs+cor;
cor=(cs-res)+cor;
return (res==res+1.020*cor)? res : cslow2(x);
} /* else if (k < 0x3feb6000) */
else if (k < 0x400368fd ) {/* 0.855469 <|x|<2.426265 */;
y=hp0.x()-ABS(x);
a=y+hp1.x();
da=(y-a)+hp1.x();
xx=a*a;
if (xx < 0.01588) {
t = (((((s5.x()*xx + s4.x())*xx + s3.x())*xx + s2.x())*xx + s1.x())*a - 0.5*da)*xx+da;
res = a+t;
cor = (a-res)+t;
cor = (cor>0)? 1.02*cor+1.0e-31 : 1.02*cor -1.0e-31;
return (res == res + cor)? res : csloww(a,da,x);
}
else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -