File indexing completed on 2024-05-12 15:27:09
0001 /*************************************************************************** 0002 File : nsl_sf_basic.c 0003 Project : LabPlot 0004 Description : NSL special basic functions 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2018-2020 by Stefan Gerlach (stefan.gerlach@uni.kn) 0007 0008 ***************************************************************************/ 0009 0010 /*************************************************************************** 0011 * * 0012 * This program is free software; you can redistribute it and/or modify * 0013 * it under the terms of the GNU General Public License as published by * 0014 * the Free Software Foundation; either version 2 of the License, or * 0015 * (at your option) any later version. * 0016 * * 0017 * This program is distributed in the hope that it will be useful, * 0018 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0020 * GNU General Public License for more details. * 0021 * * 0022 * You should have received a copy of the GNU General Public License * 0023 * along with this program; if not, write to the Free Software * 0024 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0025 * Boston, MA 02110-1301 USA * 0026 * * 0027 ***************************************************************************/ 0028 0029 #include "nsl_sf_basic.h" 0030 #include <stdlib.h> 0031 #include <math.h> 0032 #include <gsl/gsl_math.h> 0033 #include <gsl/gsl_sf.h> 0034 #include <gsl/gsl_randist.h> 0035 #ifdef HAVE_LIBCERF 0036 #include <cerf.h> 0037 #elif !defined(_MSC_VER) 0038 #include "Faddeeva.h" 0039 #endif 0040 0041 /* stdlib.h */ 0042 double nsl_sf_rand(void) { return rand(); } 0043 #if defined(HAVE_RANDOM_FUNCTION) 0044 double nsl_sf_random(void) { return random(); } 0045 double nsl_sf_drand(void) { return random()/(double)RAND_MAX; } 0046 #else 0047 double nsl_sf_random(void) { return rand(); } 0048 double nsl_sf_drand(void) { return rand()/(double)RAND_MAX; } 0049 #endif 0050 0051 double nsl_sf_sgn(double x) { 0052 #ifndef _WIN32 0053 return copysign(1.0, x); 0054 #else 0055 if (x == 0) 0056 return 0; 0057 else 0058 return GSL_SIGN(x); 0059 #endif 0060 } 0061 0062 double nsl_sf_theta(double x) { 0063 if (x >= 0) 0064 return 1; 0065 else 0066 return 0; 0067 } 0068 0069 /* 0070 * source: https://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers 0071 * source: https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup 0072 */ 0073 int nsl_sf_log2_int(unsigned int x) { 0074 #ifdef _MSC_VER 0075 return nsl_sf_log2_int2(x); 0076 #else 0077 return nsl_sf_log2_int0(x); 0078 #endif 0079 } 0080 int nsl_sf_log2_int0(unsigned int x) { 0081 #ifdef _MSC_VER 0082 return 0; /* not implemented yet */ 0083 #else 0084 return (int) (8*sizeof (unsigned int) - __builtin_clz(x) - 1); 0085 #endif 0086 } 0087 int nsl_sf_log2_int2(int x) { 0088 const signed char LogTable256[256] = { 0089 -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 0090 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 0091 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 0092 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 0093 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 0094 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 0095 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 0096 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 0097 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0098 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0099 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0100 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0101 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0102 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0103 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0104 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 0105 }; 0106 0107 unsigned int r; // r will be lg(v) 0108 unsigned int t, tt; // temporaries 0109 if ((tt = x >> 16)) 0110 r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt]; 0111 else 0112 r = (t = x >> 8) ? 8 + LogTable256[t] : LogTable256[x]; 0113 0114 return r; 0115 } 0116 int nsl_sf_log2_int3(uint64_t value) { 0117 const int tab64[64] = { 0118 63, 0, 58, 1, 59, 47, 53, 2, 0119 60, 39, 48, 27, 54, 33, 42, 3, 0120 61, 51, 37, 40, 49, 18, 28, 20, 0121 55, 30, 34, 11, 43, 14, 22, 4, 0122 62, 57, 46, 52, 38, 26, 32, 41, 0123 50, 36, 17, 19, 29, 10, 13, 21, 0124 56, 45, 25, 31, 35, 16, 9, 12, 0125 44, 24, 15, 8, 23, 7, 6, 5}; 0126 0127 value |= value >> 1; 0128 value |= value >> 2; 0129 value |= value >> 4; 0130 value |= value >> 8; 0131 value |= value >> 16; 0132 value |= value >> 32; 0133 0134 return tab64[((uint64_t)((value - (value >> 1))*0x07EDD5E59A4E28C2)) >> 58]; 0135 } 0136 int nsl_sf_log2p1_int(int x) { 0137 // fastest method 0138 return nsl_sf_log2_int(x) + 1; 0139 //TODO: why is this so slow 0140 //return (int)log2(x) + 1; 0141 } 0142 int nsl_sf_log2_longlong(unsigned long long x) { 0143 #ifdef _MSC_VER 0144 return 0; /* not implemented yet */ 0145 #else 0146 return (int) (8*sizeof (unsigned long long) - __builtin_clzll(x) - 1); 0147 #endif 0148 } 0149 0150 double nsl_sf_sec(double x) { return 1./cos(x); } 0151 double nsl_sf_csc(double x) { return 1./sin(x); } 0152 double nsl_sf_cot(double x) { return 1./tan(x); } 0153 double nsl_sf_asec(double x) { return acos(1./x); } 0154 double nsl_sf_acsc(double x) { return asin(1./x); } 0155 double nsl_sf_acot(double x) { 0156 if (x > 0) 0157 return atan(1./x); 0158 else 0159 return atan(1./x) + M_PI; 0160 } 0161 double nsl_sf_sech(double x) { return 1./cosh(x); } 0162 double nsl_sf_csch(double x) { return 1./sinh(x); } 0163 double nsl_sf_coth(double x) { return 1./tanh(x); } 0164 double nsl_sf_asech(double x) { return gsl_acosh(1./x); } 0165 double nsl_sf_acsch(double x) { return gsl_asinh(1./x); } 0166 double nsl_sf_acoth(double x) { return gsl_atanh(1./x); } 0167 0168 double nsl_sf_harmonic(double x) { 0169 // check if x is a negative integer 0170 if (x < 0 && !gsl_fcmp(round(x) - x, 0., 1.e-16)) 0171 return GSL_POSINF; 0172 0173 return gsl_sf_psi(x + 1) + M_EULER; 0174 } 0175 0176 /* error functions and related */ 0177 double nsl_sf_erfcx(double x) { 0178 #ifdef HAVE_LIBCERF 0179 return erfcx(x); 0180 #elif defined(_MSC_VER) 0181 return 0.; // not supported yet 0182 #else 0183 return Faddeeva_erfcx_re(x); 0184 #endif 0185 } 0186 0187 double nsl_sf_erfi(double x) { 0188 #ifdef HAVE_LIBCERF 0189 return erfi(x); 0190 #elif defined(_MSC_VER) 0191 return 0.; // not supported yet 0192 #else 0193 return Faddeeva_erfi_re(x); 0194 #endif 0195 } 0196 0197 double nsl_sf_im_w_of_x(double x) { 0198 #ifdef HAVE_LIBCERF 0199 return im_w_of_x(x); 0200 #elif defined(_MSC_VER) 0201 return 0.; // not supported yet 0202 #else 0203 return Faddeeva_w_im(x); 0204 #endif 0205 } 0206 0207 #if !defined(_MSC_VER) 0208 double nsl_sf_im_w_of_z(COMPLEX z) { 0209 #ifdef HAVE_LIBCERF 0210 return cimag(w_of_z(z)); 0211 #else 0212 return cimag(Faddeeva_w(z, 0)); 0213 #endif 0214 } 0215 #endif 0216 0217 double nsl_sf_dawson(double x) { 0218 #ifdef HAVE_LIBCERF 0219 return dawson(x); 0220 #elif defined(_MSC_VER) 0221 return 0.; // not supported yet 0222 #else 0223 return Faddeeva_Dawson_re(x); 0224 #endif 0225 } 0226 0227 double nsl_sf_voigt(double x, double sigma, double gamma) { 0228 #ifdef HAVE_LIBCERF 0229 return voigt(x, sigma, gamma); 0230 #elif defined(_MSC_VER) 0231 return 0.; // not supported yet 0232 #else 0233 COMPLEX z = (x + I*gamma)/(sqrt(2.)*sigma); 0234 return creal(Faddeeva_w(z, 0))/(M_SQRT2*M_SQRTPI*sigma); 0235 #endif 0236 } 0237 0238 double nsl_sf_pseudovoigt(double x, double eta, double sigma, double gamma) { 0239 if (sigma == 0 || gamma == 0) 0240 return 0; 0241 //TODO: what if eta < 0 or > 1? 0242 0243 return (1. - eta) * gsl_ran_gaussian_pdf(x, sigma) + eta * gsl_ran_cauchy_pdf(x, gamma); 0244 } 0245 0246 double nsl_sf_pseudovoigt1(double x, double eta, double w) { 0247 // 2w - FWHM, sigma_G = w/sqrt(2ln(2)) 0248 return nsl_sf_pseudovoigt(x, eta, w/sqrt(2.*log(2.)), w); 0249 } 0250 0251 /* wrapper for GSL functions with integer parameters */ 0252 #define MODE GSL_PREC_DOUBLE 0253 /* mathematical functions */ 0254 double nsl_sf_ldexp(double x, double expo) { return gsl_ldexp(x, (int)round(expo)); } 0255 double nsl_sf_powint(double x, double n) { return gsl_sf_pow_int(x, (int)round(n)); } 0256 /* Airy functions */ 0257 double nsl_sf_airy_Ai(double x) { return gsl_sf_airy_Ai(x, MODE); } 0258 double nsl_sf_airy_Bi(double x) { return gsl_sf_airy_Bi(x, MODE); } 0259 double nsl_sf_airy_Ais(double x) { return gsl_sf_airy_Ai_scaled(x, MODE); } 0260 double nsl_sf_airy_Bis(double x) { return gsl_sf_airy_Bi_scaled(x, MODE); } 0261 double nsl_sf_airy_Aid(double x) { return gsl_sf_airy_Ai_deriv(x, MODE); } 0262 double nsl_sf_airy_Bid(double x) { return gsl_sf_airy_Bi_deriv(x, MODE); } 0263 double nsl_sf_airy_Aids(double x) { return gsl_sf_airy_Ai_deriv_scaled(x, MODE); } 0264 double nsl_sf_airy_Bids(double x) { return gsl_sf_airy_Bi_deriv_scaled(x, MODE); } 0265 double nsl_sf_airy_0_Ai(double s) { return gsl_sf_airy_zero_Ai((unsigned int)round(s)); } 0266 double nsl_sf_airy_0_Bi(double s) { return gsl_sf_airy_zero_Bi((unsigned int)round(s)); } 0267 double nsl_sf_airy_0_Aid(double s) { return gsl_sf_airy_zero_Ai_deriv((unsigned int)round(s)); } 0268 double nsl_sf_airy_0_Bid(double s) { return gsl_sf_airy_zero_Bi_deriv((unsigned int)round(s)); } 0269 /* Bessel functions */ 0270 double nsl_sf_bessel_Jn(double n, double x) { return gsl_sf_bessel_Jn((int)round(n), x); } 0271 double nsl_sf_bessel_Yn(double n, double x) { return gsl_sf_bessel_Yn((int)round(n), x); } 0272 double nsl_sf_bessel_In(double n, double x) { return gsl_sf_bessel_In((int)round(n), x); } 0273 double nsl_sf_bessel_Ins(double n, double x) { return gsl_sf_bessel_In_scaled((int)round(n), x); } 0274 double nsl_sf_bessel_Kn(double n, double x) { return gsl_sf_bessel_Kn((int)round(n), x); } 0275 double nsl_sf_bessel_Kns(double n, double x) { return gsl_sf_bessel_Kn_scaled((int)round(n), x); } 0276 double nsl_sf_bessel_jl(double l, double x) { return gsl_sf_bessel_jl((int)round(l), x); } 0277 double nsl_sf_bessel_yl(double l, double x) { return gsl_sf_bessel_yl((int)round(l), x); } 0278 double nsl_sf_bessel_ils(double l, double x) { return gsl_sf_bessel_il_scaled((int)round(l), x); } 0279 double nsl_sf_bessel_kls(double l, double x) { return gsl_sf_bessel_kl_scaled((int)round(l), x); } 0280 double nsl_sf_bessel_0_J0(double s) { return gsl_sf_bessel_zero_J0((unsigned int)round(s)); } 0281 double nsl_sf_bessel_0_J1(double s) { return gsl_sf_bessel_zero_J1((unsigned int)round(s)); } 0282 double nsl_sf_bessel_0_Jnu(double nu, double s) { return gsl_sf_bessel_zero_Jnu(nu, (unsigned int)round(s)); } 0283 0284 double nsl_sf_hydrogenicR(double n, double l, double z, double r) { return gsl_sf_hydrogenicR((int)round(n), (int)round(l), z, r); } 0285 /* elliptic integrals */ 0286 double nsl_sf_ellint_Kc(double x) { return gsl_sf_ellint_Kcomp(x, MODE); } 0287 double nsl_sf_ellint_Ec(double x) { return gsl_sf_ellint_Ecomp(x, MODE); } 0288 double nsl_sf_ellint_Pc(double x, double n) { return gsl_sf_ellint_Pcomp(x, n, MODE); } 0289 double nsl_sf_ellint_F(double phi, double k) { return gsl_sf_ellint_F(phi, k, MODE); } 0290 double nsl_sf_ellint_E(double phi, double k) { return gsl_sf_ellint_E(phi, k, MODE); } 0291 double nsl_sf_ellint_P(double phi, double k, double n) { return gsl_sf_ellint_P(phi, k, n, MODE); } 0292 double nsl_sf_ellint_D(double phi, double k) { 0293 #if GSL_MAJOR_VERSION >= 2 0294 return gsl_sf_ellint_D(phi,k,MODE); 0295 #else 0296 return gsl_sf_ellint_D(phi,k,0.0,MODE); 0297 #endif 0298 } 0299 double nsl_sf_ellint_RC(double x, double y) { return gsl_sf_ellint_RC(x, y, MODE); } 0300 double nsl_sf_ellint_RD(double x, double y, double z) { return gsl_sf_ellint_RD(x, y, z, MODE); } 0301 double nsl_sf_ellint_RF(double x, double y, double z) { return gsl_sf_ellint_RF(x, y, z, MODE); } 0302 double nsl_sf_ellint_RJ(double x, double y, double z, double p) { return gsl_sf_ellint_RJ(x, y, z, p, MODE); } 0303 0304 double nsl_sf_exprel_n(double n, double x) { return gsl_sf_exprel_n((int)round(n), x); } 0305 double nsl_sf_fermi_dirac_int(double j, double x) { return gsl_sf_fermi_dirac_int((int)round(j), x); } 0306 /* Gamma */ 0307 double nsl_sf_fact(double n) { return gsl_sf_fact((unsigned int)round(n)); } 0308 double nsl_sf_doublefact(double n) { return gsl_sf_doublefact((unsigned int)round(n)); } 0309 double nsl_sf_lnfact(double n) { return gsl_sf_lnfact((unsigned int)round(n)); } 0310 double nsl_sf_lndoublefact(double n) { return gsl_sf_lndoublefact((unsigned int)round(n)); } 0311 double nsl_sf_choose(double n, double m) { return gsl_sf_choose((unsigned int)round(n), (unsigned int)round(m)); } 0312 double nsl_sf_lnchoose(double n, double m) { return gsl_sf_lnchoose((unsigned int)round(n), (unsigned int)round(m)); } 0313 double nsl_sf_taylorcoeff(double n, double x) { return gsl_sf_taylorcoeff((int)round(n), x); } 0314 0315 double nsl_sf_gegenpoly_n(double n, double l, double x) { return gsl_sf_gegenpoly_n((int)round(n), l, x); } 0316 0317 #if (GSL_MAJOR_VERSION > 2) || (GSL_MAJOR_VERSION == 2) && (GSL_MINOR_VERSION >= 4) 0318 double nsl_sf_hermite_prob(double n, double x) { return gsl_sf_hermite_prob((int)round(n), x); } 0319 double nsl_sf_hermite_phys(double n, double x) { return gsl_sf_hermite_phys((int)round(n), x); } 0320 double nsl_sf_hermite_func(double n, double x) { return gsl_sf_hermite_func((int)round(n), x); } 0321 double nsl_sf_hermite_prob_der(double m, double n, double x) { return gsl_sf_hermite_prob_der((int)round(m), (int)round(n), x); } 0322 double nsl_sf_hermite_phys_der(double m, double n, double x) { return gsl_sf_hermite_phys_der((int)round(m), (int)round(n), x); } 0323 double nsl_sf_hermite_func_der(double m, double n, double x) { return gsl_sf_hermite_func_der((int)round(m), (int)round(n), x); } 0324 #endif 0325 0326 double nsl_sf_hyperg_1F1i(double m, double n, double x) { return gsl_sf_hyperg_1F1_int((int)round(m), (int)round(n), x); } 0327 double nsl_sf_hyperg_Ui(double m, double n, double x) { return gsl_sf_hyperg_U_int((int)round(m), (int)round(n), x); } 0328 double nsl_sf_laguerre_n(double n, double a, double x) { return gsl_sf_laguerre_n((int)round(n), a, x); } 0329 0330 double nsl_sf_legendre_Pl(double l, double x) { return gsl_sf_legendre_Pl((int)round(l), x); } 0331 double nsl_sf_legendre_Ql(double l, double x) { return gsl_sf_legendre_Ql((int)round(l), x); } 0332 double nsl_sf_legendre_Plm(double l, double m, double x) { return gsl_sf_legendre_Plm((int)round(l), (int)round(m), x); } 0333 double nsl_sf_legendre_sphPlm(double l, double m, double x) { return gsl_sf_legendre_sphPlm((int)round(l), (int)round(m), x); } 0334 double nsl_sf_conicalP_sphreg(double l, double L, double x) { return gsl_sf_conicalP_sph_reg((int)round(l), L, x); } 0335 double nsl_sf_conicalP_cylreg(double m, double l, double x) { return gsl_sf_conicalP_sph_reg((int)round(m), l, x); } 0336 double nsl_sf_legendre_H3d(double l, double L, double e) { return gsl_sf_legendre_H3d((int)round(l), L, e); } 0337 0338 double nsl_sf_psiint(double n) { return gsl_sf_psi_int((int)round(n)); } 0339 double nsl_sf_psi1int(double n) { return gsl_sf_psi_1_int((int)round(n)); } 0340 double nsl_sf_psin(double n, double x) { return gsl_sf_psi_n((int)round(n), x); } 0341 0342 double nsl_sf_zetaint(double n) { return gsl_sf_zeta_int((int)round(n)); } 0343 double nsl_sf_zetam1int(double n) { return gsl_sf_zetam1_int((int)round(n)); } 0344 double nsl_sf_etaint(double n) { return gsl_sf_eta_int((int)round(n)); } 0345 0346 /* random number distributions */ 0347 double nsl_sf_poisson(double k, double m) { return gsl_ran_poisson_pdf((unsigned int)round(k), m); } 0348 double nsl_sf_bernoulli(double k, double p) { return gsl_ran_bernoulli_pdf((unsigned int)round(k), p); } 0349 double nsl_sf_binomial(double k, double p, double n) { return gsl_ran_binomial_pdf((unsigned int)round(k), p, (unsigned int)round(n)); } 0350 double nsl_sf_negative_binomial(double k, double p, double n) { return gsl_ran_negative_binomial_pdf((unsigned int)round(k), p, n); } 0351 double nsl_sf_pascal(double k, double p, double n) { return gsl_ran_pascal_pdf((unsigned int)round(k), p, (unsigned int)round(n)); } 0352 double nsl_sf_geometric(double k, double p) { return gsl_ran_geometric_pdf((unsigned int)round(k), p); } 0353 double nsl_sf_hypergeometric(double k, double n1, double n2, double t) { 0354 return gsl_ran_hypergeometric_pdf((unsigned int)round(k), (unsigned int)round(n1), (unsigned int)round(n2), (unsigned int)round(t)); 0355 } 0356 double nsl_sf_logarithmic(double k, double p) { return gsl_ran_logarithmic_pdf((unsigned int)round(k), p); }