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); }