Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-15 09:25:50

0001 #ifndef ROOT_VectorizedTMath
0002 #define ROOT_VectorizedTMath
0003 
0004 #include "Math/Types.h"
0005 #include "RConfigure.h" // for R__HAS_STD_EXPERIMENTAL_SIMD
0006 
0007 #ifdef R__HAS_STD_EXPERIMENTAL_SIMD
0008 
0009 #include <cmath>
0010 
0011 namespace TMath {
0012 
0013 template <class T, class Abi>
0014 auto Log2(std::experimental::simd<T, Abi> &x)
0015 {
0016    return log2(x);
0017 }
0018 
0019 /// Calculate a Breit Wigner function with mean and gamma.
0020 template <class T, class Abi>
0021 auto BreitWigner(std::experimental::simd<T, Abi> &x, double mean = 0, double gamma = 1)
0022 {
0023    return 0.5 * M_1_PI * (gamma / (0.25 * gamma * gamma + (x - mean) * (x - mean)));
0024 }
0025 
0026 /// Calculate a gaussian function with mean and sigma.
0027 /// If norm=kTRUE (default is kFALSE) the result is divided
0028 /// by sqrt(2*Pi)*sigma.
0029 template <class T, class Abi>
0030 auto Gaus(std::experimental::simd<T, Abi> &x, double mean = 0, double sigma = 1, Bool_t norm = false)
0031 {
0032    if (sigma == 0)
0033       return std::experimental::simd<T, Abi>{1.e30};
0034 
0035    auto inv_sigma = 1.0 / std::experimental::simd<T, Abi>(sigma);
0036    auto arg = (x - std::experimental::simd<T, Abi>(mean)) * inv_sigma;
0037 
0038    // For those entries of |arg| > 39 result is zero in double precision
0039    std::experimental::simd<T, Abi> out{};
0040    where(abs(arg) < 39.0, out) = exp(std::experimental::simd<T, Abi>(-0.5) * arg * arg);
0041 
0042    if (norm)
0043       out *= 0.3989422804014327 * inv_sigma; // 1/sqrt(2*Pi)=0.3989422804014327
0044    return out;
0045 }
0046 
0047 /// Computes the probability density function of Laplace distribution
0048 /// at point x, with location parameter alpha and shape parameter beta.
0049 /// By default, alpha=0, beta=1
0050 /// This distribution is known under different names, most common is
0051 /// double exponential distribution, but it also appears as
0052 /// the two-tailed exponential or the bilateral exponential distribution
0053 template <class T, class Abi>
0054 auto LaplaceDist(std::experimental::simd<T, Abi> &x, double alpha = 0, double beta = 1)
0055 {
0056    auto beta_v_inv = std::experimental::simd<T, Abi>(1.0 / beta);
0057    auto out = exp(-abs((x - alpha) * beta_v_inv));
0058    out *= 0.5 * beta_v_inv;
0059    return out;
0060 }
0061 
0062 /// Computes the distribution function of Laplace distribution
0063 /// at point x, with location parameter alpha and shape parameter beta.
0064 /// By default, alpha=0, beta=1
0065 /// This distribution is known under different names, most common is
0066 /// double exponential distribution, but it also appears as
0067 /// the two-tailed exponential or the bilateral exponential distribution
0068 template <class T, class Abi>
0069 auto LaplaceDistI(std::experimental::simd<T, Abi> &x, double alpha = 0, double beta = 1)
0070 {
0071    auto alpha_v = std::experimental::simd<T, Abi>(alpha);
0072    auto beta_v_inv = std::experimental::simd<T, Abi>(1.0) / std::experimental::simd<T, Abi>(beta);
0073    auto mask = x <= alpha_v;
0074    std::experimental::simd<T, Abi> out{};
0075    where(mask, out) = 0.5 * exp(-abs((x - alpha_v) * beta_v_inv));
0076    where(!mask, out) = 1 - 0.5 * exp(-abs((x - alpha_v) * beta_v_inv));
0077    return out;
0078 }
0079 
0080 /// Computation of the normal frequency function freq(x).
0081 /// Freq(x) = (1/sqrt(2pi)) Integral(exp(-t^2/2))dt between -infinity and x.
0082 ///
0083 /// Translated from CERNLIB C300 by Rene Brun.
0084 template <class T, class Abi>
0085 auto Freq(std::experimental::simd<T, Abi> &x)
0086 {
0087    double c1 = 0.56418958354775629;
0088    double w2 = 1.41421356237309505;
0089 
0090    double p10 = 2.4266795523053175e+2, q10 = 2.1505887586986120e+2, p11 = 2.1979261618294152e+1,
0091           q11 = 9.1164905404514901e+1, p12 = 6.9963834886191355e+0, q12 = 1.5082797630407787e+1,
0092           p13 = -3.5609843701815385e-2;
0093 
0094    double p20 = 3.00459261020161601e+2, q20 = 3.00459260956983293e+2, p21 = 4.51918953711872942e+2,
0095           q21 = 7.90950925327898027e+2, p22 = 3.39320816734343687e+2, q22 = 9.31354094850609621e+2,
0096           p23 = 1.52989285046940404e+2, q23 = 6.38980264465631167e+2, p24 = 4.31622272220567353e+1,
0097           q24 = 2.77585444743987643e+2, p25 = 7.21175825088309366e+0, q25 = 7.70001529352294730e+1,
0098           p26 = 5.64195517478973971e-1, q26 = 1.27827273196294235e+1, p27 = -1.36864857382716707e-7;
0099 
0100    double p30 = -2.99610707703542174e-3, q30 = 1.06209230528467918e-2, p31 = -4.94730910623250734e-2,
0101           q31 = 1.91308926107829841e-1, p32 = -2.26956593539686930e-1, q32 = 1.05167510706793207e+0,
0102           p33 = -2.78661308609647788e-1, q33 = 1.98733201817135256e+0, p34 = -2.23192459734184686e-2, q34 = 1;
0103 
0104    auto v = abs(x) / w2;
0105 
0106    std::experimental::simd<T, Abi> result{};
0107 
0108    auto mask1 = v < 0.5;
0109    auto mask2 = !mask1 && v < 4.0;
0110    auto mask3 = !(mask1 || mask2);
0111 
0112    auto v2 = v * v;
0113    auto v3 = v2 * v;
0114    auto v4 = v3 * v;
0115    auto v5 = v4 * v;
0116    auto v6 = v5 * v;
0117    auto v7 = v6 * v;
0118    auto v8 = v7 * v;
0119 
0120    where(mask1, result) = v * (p10 + p11 * v2 + p12 * v4 + p13 * v6) / (q10 + q11 * v2 + q12 * v4 + v6);
0121    where(mask2, result) =
0122       1.0 - (p20 + p21 * v + p22 * v2 + p23 * v3 + p24 * v4 + p25 * v5 + p26 * v6 + p27 * v7) /
0123                (exp(v2) * (q20 + q21 * v + q22 * v2 + q23 * v3 + q24 * v4 + q25 * v5 + q26 * v6 + v7));
0124    where(mask3, result) = 1.0 - (c1 + (p30 * v8 + p31 * v6 + p32 * v4 + p33 * v2 + p34) /
0125                                          ((q30 * v8 + q31 * v6 + q32 * v4 + q33 * v2 + q34) * v2)) /
0126                                    (v * exp(v2));
0127 
0128    auto out = 0.5 * (1 - result);
0129    where(x > 0, out) = 0.5 + 0.5 * result;
0130    return out;
0131 }
0132 
0133 /// Vectorized implementation of Bessel function I_0(x) for a vector x.
0134 template <class T, class Abi>
0135 auto BesselI0_Split_More(std::experimental::simd<T, Abi> &ax)
0136 {
0137    auto y = 3.75 / ax;
0138    return (exp(ax) / sqrt(ax)) *
0139           (0.39894228 +
0140            y * (1.328592e-2 +
0141                 y * (2.25319e-3 +
0142                      y * (-1.57565e-3 +
0143                           y * (9.16281e-3 +
0144                                y * (-2.057706e-2 + y * (2.635537e-2 + y * (-1.647633e-2 + y * 3.92377e-3))))))));
0145 }
0146 
0147 template <class T, class Abi>
0148 auto BesselI0_Split_Less(std::experimental::simd<T, Abi> &x)
0149 {
0150    auto y = x * x * 0.071111111;
0151 
0152    return 1.0 +
0153           y * (3.5156229 + y * (3.0899424 + y * (1.2067492 + y * (0.2659732 + y * (3.60768e-2 + y * 4.5813e-3)))));
0154 }
0155 
0156 template <class T, class Abi>
0157 auto BesselI0(std::experimental::simd<T, Abi> &x)
0158 {
0159    auto ax = abs(x);
0160 
0161    auto out = BesselI0_Split_More(ax);
0162    where(ax <= 3.75, out) = BesselI0_Split_Less(x);
0163    return out;
0164 }
0165 
0166 ///  Vectorized implementation of modified Bessel function I_1(x) for a vector x.
0167 template <class T, class Abi>
0168 auto BesselI1_Split_More(std::experimental::simd<T, Abi> &ax, std::experimental::simd<T, Abi> &x)
0169 {
0170    auto y = 3.75 / ax;
0171    auto result = (exp(ax) / sqrt(ax)) *
0172                  (0.39894228 +
0173                   y * (-3.988024e-2 +
0174                        y * (-3.62018e-3 +
0175                             y * (1.63801e-3 +
0176                                  y * (-1.031555e-2 +
0177                                       y * (2.282967e-2 + y * (-2.895312e-2 + y * (1.787654e-2 + y * -4.20059e-3))))))));
0178    where(x < 0, result) = -result;
0179    return result;
0180 }
0181 
0182 template <class T, class Abi>
0183 auto BesselI1_Split_Less(std::experimental::simd<T, Abi> &x)
0184 {
0185    auto y = x * x * 0.071111111;
0186 
0187    return x * (0.5 + y * (0.87890594 +
0188                           y * (0.51498869 + y * (0.15084934 + y * (2.658733e-2 + y * (3.01532e-3 + y * 3.2411e-4))))));
0189 }
0190 
0191 template <class T, class Abi>
0192 auto BesselI1(std::experimental::simd<T, Abi> &x)
0193 {
0194    auto ax = abs(x);
0195 
0196    auto out = BesselI1_Split_More(ax, x);
0197    where(ax <= 3.75, out) = BesselI1_Split_Less(x);
0198    return out;
0199 }
0200 
0201 ///  Vectorized implementation of Bessel function J0(x) for a vector x.
0202 template <class T, class Abi>
0203 auto BesselJ0_Split1_More(std::experimental::simd<T, Abi> &ax)
0204 {
0205    auto z = 8 / ax;
0206    auto y = z * z;
0207    auto xx = ax - 0.785398164;
0208    auto result1 = 1 + y * (-0.1098628627e-2 + y * (0.2734510407e-4 + y * (-0.2073370639e-5 + y * 0.2093887211e-6)));
0209    auto result2 =
0210       -0.1562499995e-1 + y * (0.1430488765e-3 + y * (-0.6911147651e-5 + y * (0.7621095161e-6 - y * 0.934935152e-7)));
0211    return sqrt(0.636619772 / ax) * (cos(xx) * result1 - z * sin(xx) * result2);
0212 }
0213 
0214 template <class T, class Abi>
0215 auto BesselJ0_Split1_Less(std::experimental::simd<T, Abi> &x)
0216 {
0217    auto y = x * x;
0218    return (57568490574.0 +
0219            y * (-13362590354.0 + y * (651619640.7 + y * (-11214424.18 + y * (77392.33017 + y * -184.9052456))))) /
0220           (57568490411.0 + y * (1029532985.0 + y * (9494680.718 + y * (59272.64853 + y * (267.8532712 + y)))));
0221 }
0222 
0223 template <class T, class Abi>
0224 auto BesselJ0(std::experimental::simd<T, Abi> &x)
0225 {
0226    auto ax = abs(x);
0227    auto out = BesselJ0_Split1_More(ax);
0228    where(ax < 8, out) = BesselJ0_Split1_Less(x);
0229    return out;
0230 }
0231 
0232 ///  Vectorized implementation of Bessel function J1(x) for a vector x.
0233 template <class T, class Abi>
0234 auto BesselJ1_Split1_More(std::experimental::simd<T, Abi> &ax, std::experimental::simd<T, Abi> &x)
0235 {
0236    auto z = 8 / ax;
0237    auto y = z * z;
0238    auto xx = ax - 2.356194491;
0239    auto result1 = 1 + y * (0.183105e-2 + y * (-0.3516396496e-4 + y * (0.2457520174e-5 + y * -0.240337019e-6)));
0240    auto result2 =
0241       0.04687499995 + y * (-0.2002690873e-3 + y * (0.8449199096e-5 + y * (-0.88228987e-6 - y * 0.105787412e-6)));
0242    auto result = sqrt(0.636619772 / ax) * (cos(xx) * result1 - z * sin(xx) * result2);
0243    where(x < 0, result) = -result;
0244    return result;
0245 }
0246 
0247 template <class T, class Abi>
0248 auto BesselJ1_Split1_Less(std::experimental::simd<T, Abi> &x)
0249 {
0250    auto y = x * x;
0251    return x *
0252           (72362614232.0 +
0253            y * (-7895059235.0 + y * (242396853.1 + y * (-2972611.439 + y * (15704.48260 + y * -30.16036606))))) /
0254           (144725228442.0 + y * (2300535178.0 + y * (18583304.74 + y * (99447.43394 + y * (376.9991397 + y)))));
0255 }
0256 
0257 template <class T, class Abi>
0258 auto BesselJ1(std::experimental::simd<T, Abi> &x)
0259 {
0260    auto ax = abs(x);
0261    auto out = BesselJ1_Split1_More(ax, x);
0262    where(ax < 8, out) = BesselJ1_Split1_Less(x);
0263    return out;
0264 }
0265 
0266 } // namespace TMath
0267 
0268 #endif // R__HAS_STD_EXPERIMENTAL_SIMD
0269 
0270 #endif