File size: 4,362 Bytes
7885a28 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
/* Translated from Cython into C++ by SciPy developers in 2023.
*
* Original author: Josh Wilson, 2016.
*/
/* Implement sin(pi*z) and cos(pi*z) for complex z. Since the periods
* of these functions are integral (and thus better representable in
* floating point), it's possible to compute them with greater accuracy
* than sin(z), cos(z).
*/
#pragma once
#include "cephes/sindg.h"
#include "cephes/tandg.h"
#include "cephes/trig.h"
#include "cephes/unity.h"
#include "config.h"
#include "evalpoly.h"
namespace xsf {
template <typename T>
XSF_HOST_DEVICE T sinpi(T x) {
return cephes::sinpi(x);
}
template <typename T>
XSF_HOST_DEVICE std::complex<T> sinpi(std::complex<T> z) {
T x = z.real();
T piy = M_PI * z.imag();
T abspiy = std::abs(piy);
T sinpix = cephes::sinpi(x);
T cospix = cephes::cospi(x);
if (abspiy < 700) {
return {sinpix * std::cosh(piy), cospix * std::sinh(piy)};
}
/* Have to be careful--sinh/cosh could overflow while cos/sin are small.
* At this large of values
*
* cosh(y) ~ exp(y)/2
* sinh(y) ~ sgn(y)*exp(y)/2
*
* so we can compute exp(y/2), scale by the right factor of sin/cos
* and then multiply by exp(y/2) to avoid overflow. */
T exphpiy = std::exp(abspiy / 2);
T coshfac;
T sinhfac;
if (exphpiy == std::numeric_limits<T>::infinity()) {
if (sinpix == 0.0) {
// Preserve the sign of zero.
coshfac = std::copysign(0.0, sinpix);
} else {
coshfac = std::copysign(std::numeric_limits<T>::infinity(), sinpix);
}
if (cospix == 0.0) {
// Preserve the sign of zero.
sinhfac = std::copysign(0.0, cospix);
} else {
sinhfac = std::copysign(std::numeric_limits<T>::infinity(), cospix);
}
return {coshfac, sinhfac};
}
coshfac = 0.5 * sinpix * exphpiy;
sinhfac = 0.5 * cospix * exphpiy;
return {coshfac * exphpiy, sinhfac * exphpiy};
}
template <typename T>
XSF_HOST_DEVICE T cospi(T x) {
return cephes::cospi(x);
}
template <typename T>
XSF_HOST_DEVICE std::complex<T> cospi(std::complex<T> z) {
T x = z.real();
T piy = M_PI * z.imag();
T abspiy = std::abs(piy);
T sinpix = cephes::sinpi(x);
T cospix = cephes::cospi(x);
if (abspiy < 700) {
return {cospix * std::cosh(piy), -sinpix * std::sinh(piy)};
}
// See csinpi(z) for an idea of what's going on here.
T exphpiy = std::exp(abspiy / 2);
T coshfac;
T sinhfac;
if (exphpiy == std::numeric_limits<T>::infinity()) {
if (sinpix == 0.0) {
// Preserve the sign of zero.
coshfac = std::copysign(0.0, cospix);
} else {
coshfac = std::copysign(std::numeric_limits<T>::infinity(), cospix);
}
if (cospix == 0.0) {
// Preserve the sign of zero.
sinhfac = std::copysign(0.0, sinpix);
} else {
sinhfac = std::copysign(std::numeric_limits<T>::infinity(), sinpix);
}
return {coshfac, sinhfac};
}
coshfac = 0.5 * cospix * exphpiy;
sinhfac = 0.5 * sinpix * exphpiy;
return {coshfac * exphpiy, sinhfac * exphpiy};
}
template <typename T>
XSF_HOST_DEVICE T sindg(T x) {
return cephes::sindg(x);
}
template <>
XSF_HOST_DEVICE inline float sindg(float x) {
return sindg(static_cast<double>(x));
}
template <typename T>
XSF_HOST_DEVICE T cosdg(T x) {
return cephes::cosdg(x);
}
template <>
XSF_HOST_DEVICE inline float cosdg(float x) {
return cosdg(static_cast<double>(x));
}
template <typename T>
XSF_HOST_DEVICE T tandg(T x) {
return cephes::tandg(x);
}
template <>
XSF_HOST_DEVICE inline float tandg(float x) {
return tandg(static_cast<double>(x));
}
template <typename T>
XSF_HOST_DEVICE T cotdg(T x) {
return cephes::cotdg(x);
}
template <>
XSF_HOST_DEVICE inline float cotdg(float x) {
return cotdg(static_cast<double>(x));
}
inline double radian(double d, double m, double s) { return cephes::radian(d, m, s); }
inline float radian(float d, float m, float s) {
return radian(static_cast<double>(d), static_cast<double>(m), static_cast<double>(s));
}
inline double cosm1(double x) { return cephes::cosm1(x); }
inline float cosm1(float x) { return cosm1(static_cast<double>(x)); }
} // namespace xsf
|