|
Packit |
67cb25 |
/* specfunc/sincos_pi.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2017 Gerard Jungman, Konrad Griessinger (konradg@gmx.net)
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
67cb25 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
67cb25 |
* the Free Software Foundation; either version 3 of the License, or (at
|
|
Packit |
67cb25 |
* your option) any later version.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
67cb25 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
67cb25 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
67cb25 |
* General Public License for more details.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
67cb25 |
* along with this program; if not, write to the Free Software
|
|
Packit |
67cb25 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* routines for computing sin(pi*x) and cos(pi*x), respectively, with argument reduction */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include <math.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_math.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_sf_trig.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_errno.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_sf_sincos_pi.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Any double precision number bigger than this is automatically an even integer. */
|
|
Packit |
67cb25 |
#define TWOBIG (2.0 / GSL_DBL_EPSILON)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* routine computing sin(pi*x) valid for |x| <= 0.25 using a Taylor expansion around the origin and otherwise a rational approximation from the reference below. Spot-checked to give around 2e-16 relative accuracy. */
|
|
Packit |
67cb25 |
/* I. Koren and O. Zinaty. Evaluating elementary functions in a numerical
|
|
Packit |
67cb25 |
coprocessor based on rational approximations. IEEE Transactions on
|
|
Packit |
67cb25 |
Computers, Vol.39, No.8, August 1990, pp 1030-1037. */
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
sin_pi_koren(const double x, gsl_sf_result *result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
result->val = 0.0;
|
|
Packit |
67cb25 |
result->err = 0.0;
|
|
Packit |
67cb25 |
if (16.0*fabs(x) < 1.0) {
|
|
Packit |
67cb25 |
const double y = M_PI * x;
|
|
Packit |
67cb25 |
const double a = y*y;
|
|
Packit |
67cb25 |
result->val = y*(1.0 - a*(1.0 - a*(1.0 - a*(1.0 - a*(1.0 - a/110.0)/72.0)/42.0)/20.0)/6.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
const double a0 = 1805490264.690988571178600370234394843221;
|
|
Packit |
67cb25 |
const double a1 = -164384678.227499837726129612587952660511;
|
|
Packit |
67cb25 |
const double a2 = 3664210.647581261810227924465160827365;
|
|
Packit |
67cb25 |
const double a3 = -28904.140246461781357223741935980097;
|
|
Packit |
67cb25 |
const double a4 = 76.568981088717405810132543523682;
|
|
Packit |
67cb25 |
const double b0 = 2298821602.638922662086487520330827251172;
|
|
Packit |
67cb25 |
const double b1 = 27037050.118894436776624866648235591988;
|
|
Packit |
67cb25 |
const double b2 = 155791.388546947693206469423979505671;
|
|
Packit |
67cb25 |
const double b3 = 540.567501261284024767779280700089;
|
|
Packit |
67cb25 |
const double t = 16.0*x*x;
|
|
Packit |
67cb25 |
result->val = 4.0*x*(((( a4*t + a3 )*t + a2 )*t + a1 )*t + a0)/(((( t + b3 )*t + b2 )*t + b1 )*t + b0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result->err = GSL_DBL_EPSILON*fabs(result->val);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* routine computing cos(pi*x) valid for |x| <= 0.25 using a Taylor expansion around the origin and otherwise a rational approximation from the reference below. Spot-checked to give around 2e-16 relative accuracy. */
|
|
Packit |
67cb25 |
/* I. Koren and O. Zinaty. Evaluating elementary functions in a numerical
|
|
Packit |
67cb25 |
coprocessor based on rational approximations. IEEE Transactions on
|
|
Packit |
67cb25 |
Computers, Vol.39, No.8, August 1990, pp 1030-1037. */
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
cos_pi_koren(const double x, gsl_sf_result *result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
result->val = 0.0;
|
|
Packit |
67cb25 |
result->err = 0.0;
|
|
Packit |
67cb25 |
if (20.0*fabs(x) < 1.0) {
|
|
Packit |
67cb25 |
const double y = M_PI * x;
|
|
Packit |
67cb25 |
const double a = y*y;
|
|
Packit |
67cb25 |
result->val = 1.0 - 0.5*a*(1.0 - a*(1.0 - a*(1.0 - a*(1.0 - a/90.0)/56.0)/30.0)/12.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
const double a0 = 1090157078.174871420428849017262549038606;
|
|
Packit |
67cb25 |
const double a1 = -321324810.993150712401352959397648541681;
|
|
Packit |
67cb25 |
const double a2 = 12787876.849523878944051885325593878177;
|
|
Packit |
67cb25 |
const double a3 = -150026.206045948110568310887166405972;
|
|
Packit |
67cb25 |
const double a4 = 538.333564203182661664319151379451;
|
|
Packit |
67cb25 |
const double b0 = 1090157078.174871420428867295670039506886;
|
|
Packit |
67cb25 |
const double b1 = 14907035.776643879767410969509628406502;
|
|
Packit |
67cb25 |
const double b2 = 101855.811943661368302608146695082218;
|
|
Packit |
67cb25 |
const double b3 = 429.772865107391823245671264489311;
|
|
Packit |
67cb25 |
const double t = 16.0*x*x;
|
|
Packit |
67cb25 |
result->val = (((( a4*t + a3 )*t + a2 )*t + a1 )*t + a0)/(((( t + b3 )*t + b2 )*t + b1 )*t + b0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result->err = GSL_DBL_EPSILON*fabs(result->val);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* routine computing sin(pi*x) using a Taylor expansion around the origin and otherwise the library function. */
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
sin_pi_taylor(const double x, gsl_sf_result *result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
result->val = 0.0;
|
|
Packit |
67cb25 |
result->err = 0.0;
|
|
Packit |
67cb25 |
if (16.0*fabs(x) < 1.0) {
|
|
Packit |
67cb25 |
const double y = M_PI * x;
|
|
Packit |
67cb25 |
const double a = y*y;
|
|
Packit |
67cb25 |
result->val = y*(1.0 - a*(1.0 - a*(1.0 - a*(1.0 - a*(1.0 - a/110.0)/72.0)/42.0)/20.0)/6.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
result->val = sin(M_PI*x);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result->err = GSL_DBL_EPSILON*fabs(result->val);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* routine computing sin(pi*x) using a Taylor expansion around the origin and otherwise the library function. */
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
cos_pi_taylor(const double x, gsl_sf_result *result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
result->val = 0.0;
|
|
Packit |
67cb25 |
result->err = 0.0;
|
|
Packit |
67cb25 |
if (20.0*fabs(x) < 1.0) {
|
|
Packit |
67cb25 |
const double y = M_PI * x;
|
|
Packit |
67cb25 |
const double a = y*y;
|
|
Packit |
67cb25 |
result->val = 1.0 - 0.5*a*(1.0 - a*(1.0 - a*(1.0 - a*(1.0 - a/90.0)/56.0)/30.0)/12.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
result->val = cos(M_PI*x);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result->err = GSL_DBL_EPSILON*fabs(result->val);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_sin_pi_e(const double x, gsl_sf_result *result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double intx = 0.0, fracx = 0.0;
|
|
Packit |
67cb25 |
long q;
|
|
Packit |
67cb25 |
int sign = 1, status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result->val = 0.0;
|
|
Packit |
67cb25 |
result->err = 0.0;
|
|
Packit |
67cb25 |
fracx = modf(x,&intx;;
|
|
Packit |
67cb25 |
if (fracx == 0.0) return GSL_SUCCESS;
|
|
Packit |
67cb25 |
if(fabs(intx) >= TWOBIG) return GSL_SUCCESS; /* to be sure. Actually should be covered by the line above */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
q = ( ( (intx >= LONG_MIN) && (intx <= LONG_MAX) ) ? intx : fmod(intx, 2.0) );
|
|
Packit |
67cb25 |
sign = ( q % 2 ? -1 : 1 );
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* int sign = 1 - 2*((int)round(fmod(fabs(intx),2.0))); */
|
|
Packit |
67cb25 |
if (fabs(fracx) == 0.5) { /* probably unnecessary */
|
|
Packit |
67cb25 |
if (fracx < 0.0) sign = -sign;
|
|
Packit |
67cb25 |
result->val = ( sign != 1 ? -1.0 : 1.0 );
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
if (fabs(fracx) > 0.5) {
|
|
Packit |
67cb25 |
sign = -sign;
|
|
Packit |
67cb25 |
fracx = ( fracx > 0.0 ? fracx-1.0 : fracx+1.0 );
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = 0;
|
|
Packit |
67cb25 |
if (fracx > 0.25) {
|
|
Packit |
67cb25 |
status = cos_pi_taylor((fracx-0.5), result);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (fracx < -0.25) {
|
|
Packit |
67cb25 |
status = cos_pi_taylor((fracx+0.5), result);
|
|
Packit |
67cb25 |
sign = -sign;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
status = sin_pi_taylor(fracx, result);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
if (sign != 1) result->val = -result->val;
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_cos_pi_e(const double x, gsl_sf_result *result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double intx = 0.0, fracx = 0.0;
|
|
Packit |
67cb25 |
long q;
|
|
Packit |
67cb25 |
int sign = 1, status;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result->val = 0.0;
|
|
Packit |
67cb25 |
result->err = 0.0;
|
|
Packit |
67cb25 |
fracx = modf(x,&intx;;
|
|
Packit |
67cb25 |
if (fabs(fracx) == 0.5) return GSL_SUCCESS;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(fabs(intx) >= TWOBIG) {
|
|
Packit |
67cb25 |
result->val = 1.0;
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
q = ( ( (intx >= LONG_MIN) && (intx <= LONG_MAX) ) ? intx : fmod(intx, 2.0) );
|
|
Packit |
67cb25 |
sign = ( q % 2 ? -1 : 1 );
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* int sign = 1 - 2*((int)round(fmod(fabs(intx),2.0))); */
|
|
Packit |
67cb25 |
if (fracx == 0.0) { /* probably unnecessary */
|
|
Packit |
67cb25 |
result->val = ( sign != 1 ? -1.0 : 1.0 );
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
if (fabs(fracx) > 0.5) {
|
|
Packit |
67cb25 |
sign = -sign;
|
|
Packit |
67cb25 |
fracx = ( fracx > 0.0 ? fracx-1.0 : fracx+1.0 );
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
status = 0;
|
|
Packit |
67cb25 |
if (fracx > 0.25) {
|
|
Packit |
67cb25 |
status = sin_pi_taylor((fracx-0.5), result);
|
|
Packit |
67cb25 |
sign = -sign;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (fracx < -0.25) {
|
|
Packit |
67cb25 |
status = sin_pi_taylor((fracx+0.5), result);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
status = cos_pi_taylor(fracx, result);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
if (sign != 1) result->val = -result->val;
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include "eval.h"
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double
|
|
Packit |
67cb25 |
gsl_sf_sin_pi(const double x)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
EVAL_RESULT(gsl_sf_sin_pi_e(x, &result));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double
|
|
Packit |
67cb25 |
gsl_sf_cos_pi(const double x)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
EVAL_RESULT(gsl_sf_cos_pi_e(x, &result));
|
|
Packit |
67cb25 |
}
|