https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116299

--- Comment #2 from Ryan <rmaguire314 at gmail dot com> ---
It is a part of a rather large library.
How much of it do you want?
Here is the full function, in a working condition.

/*  TMPL_STATIC_INLINE macro found here.                                     
*/
#include <libtmpl/include/tmpl_config.h>

/*  The denominator of the asymptotic expansion is scaled by pi.             
*/
#define TMPL_ONE_PI (+3.14159265358979323846264338327950288419716939E+00L)

/*  Used to compute sin(pi t) and cos(pi t) simultaneously.                  
*/
extern void
tmpl_LDouble_SinCosPi(long double t, long double *sin_t, long double *cos_t);

/*  Different splitting values are needed, depending on the type. If the      *
 *  mantissa is N bits, the magic number is 2^(N - floor(N/3) + 1) + 1. This  *
 *  guarantees that for |x| > 2^floor(N/3) the high part is even, meaning     *
 *  xhi^2 / 2 is an integer. Since sin(pi x) and cos(pi x) are periodic, we   *
 *  can then discard this computation entirely. We need only concentrate on   *
 *  the lower N - floor(N/3) bits.                                           
*/
#if TMPL_LDOUBLE_TYPE == TMPL_LDOUBLE_64_BIT

/*  52-bit mantissa, value is 2^36 + 1.                                      
*/
#define TMPL_LDOUBLE_SPLIT (6.8719476737E+10L)

/*  Quadruple precision has a much large mantissa, hence a larger value.     
*/
#elif TMPL_LDOUBLE_TYPE == TMPL_LDOUBLE_128_BIT

/*  112-bit mantissa, value is 2^76 + 1.                                     
*/
#define TMPL_LDOUBLE_SPLIT (+7.5557863725914323419137E+22L)

/*  Double-double, special case, we split the higher double.                 
*/
#elif TMPL_LDOUBLE_TYPE == TMPL_LDOUBLE_DOUBLEDOUBLE

/*  Double-double, split by 2^35 + 1 (splitting as a "double").              
*/
#define TMPL_LDOUBLE_SPLIT (+3.4359738369E+10)

/*  The most common version, 80-bit extended / portable.                     
*/
#else

/*  63-bit mantissa, value is 2^43 + 1.                                      
*/
#define TMPL_LDOUBLE_SPLIT (+8.796093022209E+12L)

#endif
/*  End of double vs. extended vs. double-double vs. quadruple.              
*/

/*  Function for computing the normalized Fresnel cosine of a large input.   
*/
TMPL_STATIC_INLINE
long double tmpl_LDouble_Normalized_Fresnel_Cos_Asymptotic(long double x)
{
    /*  Use the double-double trick, split x into two parts, high and low.   
*/
#if TMPL_LDOUBLE_TYPE == TMPL_LDOUBLE_DOUBLEDOUBLE
    volatile const double x_double = (double)x;
    volatile const double split = x_double*3.4359738369E+10;
    volatile const double xhi_double = split - (split - x_double);
    const long double xhi = (long double)xhi_double;
#else
    const long double split = TMPL_LDOUBLE_SPLIT * x;
    const long double xhi = split - (split - x);
#endif
    const long double xlo = x - xhi;

    /*  The scale factor for the asymptotic expansion. For large x we only    *
     *  need the first term of the approximation.                            
*/
    const long double t = 1.0L / (TMPL_ONE_PI * x);

    /*  For large x we have xhi^2 / 2 is an even integer. Since sin(pi t)     *
     *  is periodic with period 2, the xhi^2 term can be disregarded. The     *
     *  argument we then care about is pi (2 xhi xlo + xlo^2) / 2.           
*/
    long double sin_hi, cos_hi, sin_lo, cos_lo, sin_x;

    /*  Compute sin(pi/2 (2 xhi xlo + xlo^2)) using the angle sum formula.   
*/
    tmpl_LDouble_SinCosPi(xlo * xhi, &sin_hi, &cos_hi);
    tmpl_LDouble_SinCosPi(0.5L * xlo * xlo, &sin_lo, &cos_lo);
    sin_x = cos_hi*sin_lo + cos_lo*sin_hi;

    /*  The first term of the asymptotic expansion is all that is needed.    
*/
    return 0.5L + t * sin_x;
}

Reply via email to