Blame specfunc/sincos_pi.c

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
}