Files
pip/libs/main/math/pimathbase.cpp
2022-03-18 18:06:40 +03:00

476 lines
13 KiB
C++

/*
PIP - Platform Independent Primitives
Basic mathematical functions and defines
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pimathbase.h"
#include "pitime.h"
#include <stdlib.h>
double piJ0(const double & v) {
#ifndef PIP_MATH_J0
double x = v;
double xsq;
double nn;
double pzero;
double qzero;
double p1;
double q1;
double result;
if (x < 0) x = -x;
if (x > 8.) {
double xsq_;
double p2;
double q2;
double p3;
double q3;
xsq_ = 64. / (x * x);
p2 = 0.0;
p2 = 2485.271928957404011288128951 + xsq_ * p2;
p2 = 153982.6532623911470917825993 + xsq_ * p2;
p2 = 2016135.283049983642487182349 + xsq_ * p2;
p2 = 8413041.456550439208464315611 + xsq_ * p2;
p2 = 12332384.76817638145232406055 + xsq_ * p2;
p2 = 5393485.083869438325262122897 + xsq_ * p2;
q2 = 1.0;
q2 = 2615.700736920839685159081813 + xsq_ * q2;
q2 = 156001.7276940030940592769933 + xsq_ * q2;
q2 = 2025066.801570134013891035236 + xsq_ * q2;
q2 = 8426449.050629797331554404810 + xsq_ * q2;
q2 = 12338310.22786324960844856182 + xsq_ * q2;
q2 = 5393485.083869438325560444960 + xsq_ * q2;
p3 = -0.0;
p3 = -4.887199395841261531199129300 +xsq_ * p3;
p3 = -226.2630641933704113967255053 +xsq_ * p3;
p3 = -2365.956170779108192723612816 +xsq_ * p3;
p3 = -8239.066313485606568803548860 +xsq_ * p3;
p3 = -10381.41698748464093880530341 +xsq_ * p3;
p3 = -3984.617357595222463506790588 +xsq_ * p3;
q3 = 1.0;
q3 = 408.7714673983499223402830260 + xsq_ * q3;
q3 = 15704.89191515395519392882766 + xsq_ * q3;
q3 = 156021.3206679291652539287109 + xsq_ * q3;
q3 = 533291.3634216897168722255057 + xsq_ * q3;
q3 = 666745.4239319826986004038103 + xsq_ * q3;
q3 = 255015.5108860942382983170882 + xsq_ * q3;
pzero = p2 / q2;
qzero = 8. * p3 / q3 / x;
nn = x- M_PI / 4.;
result = sqrt(2. / M_PI / x) * (pzero * cos(nn) - qzero * sin(nn));
return result;
}
xsq = x * x;
p1 = 26857.86856980014981415848441;
p1 = -40504123.71833132706360663322 + xsq * p1;
p1 = 25071582855.36881945555156435 + xsq * p1;
p1 = -8085222034853.793871199468171 + xsq * p1;
p1 = 1434354939140344.111664316553 + xsq * p1;
p1 = -136762035308817138.6865416609 + xsq * p1;
p1 = 6382059341072356562.289432465 + xsq * p1;
p1 = -117915762910761053603.8440800 + xsq * p1;
p1 = 493378725179413356181.6813446 + xsq * p1;
q1 = 1.;
q1 = 1363.063652328970604442810507 + xsq * q1;
q1 = 1114636.098462985378182402543 + xsq * q1;
q1 = 669998767.2982239671814028660 + xsq * q1;
q1 = 312304311494.1213172572469442 + xsq * q1;
q1 = 112775673967979.8507056031594 + xsq * q1;
q1 = 30246356167094626.98627330784 + xsq * q1;
q1 = 5428918384092285160.200195092 + xsq * q1;
q1 = 493378725179413356211.3278438 + xsq * q1;
return p1 / q1;
#else
return j0(v);
#endif
}
double piJ1(const double & v) {
#ifndef PIP_MATH_J1
double x = v;
double s;
double xsq;
double nn;
double pzero;
double qzero;
double p1;
double q1;
double result;
s = sign(x);
if (x < 0)
x = -x;
if (x > 8.) {
double xsq_;
double p2;
double q2;
double p3;
double q3;
xsq_ = 64.0 / (x * x);
p2 = -1611.616644324610116477412898;
p2 = -109824.0554345934672737413139 + xsq_ * p2;
p2 = -1523529.351181137383255105722 + xsq_ * p2;
p2 = -6603373.248364939109255245434 + xsq_ * p2;
p2 = -9942246.505077641195658377899 + xsq_ * p2;
p2 = -4435757.816794127857114720794 + xsq_ * p2;
q2 = 1.0;
q2 = -1455.009440190496182453565068 + xsq_ * q2;
q2 = -107263.8599110382011903063867 + xsq_ * q2;
q2 = -1511809.506634160881644546358 + xsq_ * q2;
q2 = -6585339.479723087072826915069 + xsq_ * q2;
q2 = -9934124.389934585658967556309 + xsq_ * q2;
q2 = -4435757.816794127856828016962 + xsq_ * q2;
p3 = 35.26513384663603218592175580;
p3 = 1706.375429020768002061283546 + xsq_ * p3;
p3 = 18494.26287322386679652009819 + xsq_ * p3;
p3 = 66178.83658127083517939992166 + xsq_ * p3;
p3 = 85145.16067533570196555001171 + xsq_ * p3;
p3 = 33220.91340985722351859704442 + xsq_ * p3;
q3 = 1.0;
q3 = 863.8367769604990967475517183 + xsq_ * q3;
q3 = 37890.22974577220264142952256 + xsq_ * q3;
q3 = 400294.4358226697511708610813 + xsq_ * q3;
q3 = 1419460.669603720892855755253 + xsq_ * q3;
q3 = 1819458.042243997298924553839 + xsq_ * q3;
q3 = 708712.8194102874357377502472 + xsq_ * q3;
pzero = p2 / q2;
qzero = 8 * p3 / q3 / x;
nn = x - 3 * M_PI / 4;
result = sqrt(2 / M_PI / x) * (pzero * cos(nn) - qzero * sin(nn));
if (s < 0)
result = -result;
return result;
}
xsq = sqr(x);
p1 = 2701.122710892323414856790990;
p1 = -4695753.530642995859767162166 + xsq * p1;
p1 = 3413234182.301700539091292655 + xsq * p1;
p1 = -1322983480332.126453125473247 + xsq * p1;
p1 = 290879526383477.5409737601689 + xsq * p1;
p1 = -35888175699101060.50743641413 + xsq * p1;
p1 = 2316433580634002297.931815435 + xsq * p1;
p1 = -66721065689249162980.20941484 + xsq * p1;
p1 = 581199354001606143928.050809 + xsq * p1;
q1 = 1.0;
q1 = 1606.931573481487801970916749 + xsq * q1;
q1 = 1501793.594998585505921097578 + xsq * q1;
q1 = 1013863514.358673989967045588 + xsq * q1;
q1 = 524371026216.7649715406728642 + xsq * q1;
q1 = 208166122130760.7351240184229 + xsq * q1;
q1 = 60920613989175217.46105196863 + xsq * q1;
q1 = 11857707121903209998.37113348 + xsq * q1;
q1 = 1162398708003212287858.529400 + xsq * q1;
result = s * x * p1 / q1;
return result;
#else
return j1(v);
#endif
}
double piJn(int n, const double & v) {
#ifndef PIP_MATH_JN
double x = v;
double pkm2;
double pkm1;
double pk;
double xk;
double r;
double ans;
int k;
int sg;
double result;
if (n < 0) {
n = -n;
if (n % 2 == 0)
sg = 1;
else
sg = -1;
} else
sg = 1;
if (x < 0) {
if (n % 2 != 0)
sg = -sg;
x = -x;
}
if (n == 0) {
result = sg * piJ0(x);
return result;
}
if (n == 1) {
result = sg * piJ1(x);
return result;
}
if (n == 2) {
if (x == 0)
result = 0;
else
result = sg * (2.0 * piJ1(x) / x - piJ0(x));
return result;
}
if (x < 1E-16) {
result = 0;
return result;
}
k = 53;
pk = 2 * (n + k);
ans = pk;
xk = x * x;
do {
pk = pk - 2.0;
ans = pk - xk / ans;
k = k - 1;
} while (k != 0);
ans = x / ans;
pk = 1.0;
pkm1 = 1.0 / ans;
k = n - 1;
r = 2 * k;
do {
pkm2 = (pkm1 * r - pk * x) / x;
pk = pkm1;
pkm1 = pkm2;
r = r - 2.0;
k = k - 1;
} while (k != 0);
if (fabs(pk) > fabs(pkm1))
ans = piJ1(x) / pk;
else
ans = piJ0(x) / pkm1;
result = sg * ans;
return result;
#else
return jn(n, v);
#endif
}
double piY0(const double & v) {
#ifndef PIP_MATH_Y0
double x = v;
double nn;
double xsq;
double pzero;
double qzero;
double p4;
double q4;
double result;
if (x > 8.) {
double xsq_;
double p2;
double q2;
double p3;
double q3;
xsq_ = 64.0 / (x * x);
p2 = 0.0;
p2 = 2485.271928957404011288128951 + xsq_ * p2;
p2 = 153982.6532623911470917825993 + xsq_ * p2;
p2 = 2016135.283049983642487182349 + xsq_ * p2;
p2 = 8413041.456550439208464315611 + xsq_ * p2;
p2 = 12332384.76817638145232406055 + xsq_ * p2;
p2 = 5393485.083869438325262122897 + xsq_ * p2;
q2 = 1.0;
q2 = 2615.700736920839685159081813 + xsq_ * q2;
q2 = 156001.7276940030940592769933 + xsq_ * q2;
q2 = 2025066.801570134013891035236 + xsq_ * q2;
q2 = 8426449.050629797331554404810 + xsq_ * q2;
q2 = 12338310.22786324960844856182 + xsq_ * q2;
q2 = 5393485.083869438325560444960 + xsq_ * q2;
p3 = -0.0;
p3 = -4.887199395841261531199129300 + xsq_ * p3;
p3 = -226.2630641933704113967255053 + xsq_ * p3;
p3 = -2365.956170779108192723612816 + xsq_ * p3;
p3 = -8239.066313485606568803548860 + xsq_ * p3;
p3 = -10381.41698748464093880530341 + xsq_ * p3;
p3 = -3984.617357595222463506790588 + xsq_ * p3;
q3 = 1.0;
q3 = 408.7714673983499223402830260 + xsq_ * q3;
q3 = 15704.89191515395519392882766 + xsq_ * q3;
q3 = 156021.3206679291652539287109 + xsq_ * q3;
q3 = 533291.3634216897168722255057 + xsq_ * q3;
q3 = 666745.4239319826986004038103 + xsq_ * q3;
q3 = 255015.5108860942382983170882 + xsq_ * q3;
pzero = p2 / q2;
qzero = 8 * p3 / q3 / x;
nn = x - M_PI / 4;
result = sqrt(2 / M_PI / x) * (pzero * sin(nn) + qzero * cos(nn));
return result;
}
xsq = sqr(x);
p4 = -41370.35497933148554125235152;
p4 = 59152134.65686889654273830069 + xsq * p4;
p4 = -34363712229.79040378171030138 + xsq * p4;
p4 = 10255208596863.94284509167421 + xsq * p4;
p4 = -1648605817185729.473122082537 + xsq * p4;
p4 = 137562431639934407.8571335453 + xsq * p4;
p4 = -5247065581112764941.297350814 + xsq * p4;
p4 = 65874732757195549259.99402049 + xsq * p4;
p4 = -27502866786291095837.01933175 + xsq * p4;
q4 = 1.0;
q4 = 1282.452772478993804176329391 + xsq * q4;
q4 = 1001702.641288906265666651753 + xsq * q4;
q4 = 579512264.0700729537480087915 + xsq * q4;
q4 = 261306575504.1081249568482092 + xsq * q4;
q4 = 91620380340751.85262489147968 + xsq * q4;
q4 = 23928830434997818.57439356652 + xsq * q4;
q4 = 4192417043410839973.904769661 + xsq * q4;
q4 = 372645883898616588198.9980 + xsq * q4;
result = p4 / q4 + 2 / M_PI * piJ0(x) * log(x);
return result;
#else
return y0(v);
#endif
}
double piY1(const double & v) {
#ifndef PIP_MATH_Y1
double x = v;
double nn;
double xsq;
double pzero;
double qzero;
double p4;
double q4;
double result;
if (x > 8.) {
double xsq_;
double p2;
double q2;
double p3;
double q3;
xsq_ = 64.0 / (x * x);
p2 = -1611.616644324610116477412898;
p2 = -109824.0554345934672737413139 + xsq_ * p2;
p2 = -1523529.351181137383255105722 + xsq_ * p2;
p2 = -6603373.248364939109255245434 + xsq_ * p2;
p2 = -9942246.505077641195658377899 + xsq_ * p2;
p2 = -4435757.816794127857114720794 + xsq_ * p2;
q2 = 1.0;
q2 = -1455.009440190496182453565068 + xsq_ * q2;
q2 = -107263.8599110382011903063867 + xsq_ * q2;
q2 = -1511809.506634160881644546358 + xsq_ * q2;
q2 = -6585339.479723087072826915069 + xsq_ * q2;
q2 = -9934124.389934585658967556309 + xsq_ * q2;
q2 = -4435757.816794127856828016962 + xsq_ * q2;
p3 = 35.26513384663603218592175580;
p3 = 1706.375429020768002061283546 + xsq_ * p3;
p3 = 18494.26287322386679652009819 + xsq_ * p3;
p3 = 66178.83658127083517939992166 + xsq_ * p3;
p3 = 85145.16067533570196555001171 + xsq_ * p3;
p3 = 33220.91340985722351859704442 + xsq_ * p3;
q3 = 1.0;
q3 = 863.8367769604990967475517183 + xsq_ * q3;
q3 = 37890.22974577220264142952256 + xsq_ * q3;
q3 = 400294.4358226697511708610813 + xsq_ * q3;
q3 = 1419460.669603720892855755253 + xsq_ * q3;
q3 = 1819458.042243997298924553839 + xsq_ * q3;
q3 = 708712.8194102874357377502472 + xsq_ * q3;
pzero = p2 / q2;
qzero = 8 * p3 / q3 / x;
nn = x - 3 * M_PI / 4;
result = sqrt(2 / M_PI / x) * (pzero * sin(nn) + qzero * cos(nn));
return result;
}
xsq = sqr(x);
p4 = -2108847.540133123652824139923;
p4 = 3639488548.124002058278999428 + xsq * p4;
p4 = -2580681702194.450950541426399 + xsq * p4;
p4 = 956993023992168.3481121552788 + xsq * p4;
p4 = -196588746272214065.8820322248 + xsq * p4;
p4 = 21931073399177975921.11427556 + xsq * p4;
p4 = -1212297555414509577913.561535 + xsq * p4;
p4 = 26554738314348543268942.48968 + xsq * p4;
p4 = -99637534243069222259967.44354 + xsq * p4;
q4 = 1.0;
q4 = 1612.361029677000859332072312 + xsq * q4;
q4 = 1563282.754899580604737366452 + xsq * q4;
q4 = 1128686837.169442121732366891 + xsq * q4;
q4 = 646534088126.5275571961681500 + xsq * q4;
q4 = 297663212564727.6729292742282 + xsq * q4;
q4 = 108225825940881955.2553850180 + xsq * q4;
q4 = 29549879358971486742.90758119 + xsq * q4;
q4 = 5435310377188854170800.653097 + xsq * q4;
q4 = 508206736694124324531442.4152 + xsq * q4;
result = x * p4 / q4 + 2 / M_PI * (piJ1(x) * log(x) - 1 / x);
return result;
#else
return y1(v);
#endif
}
double piYn(int n, const double & v) {
#ifndef PIP_MATH_YN
int i;
double x = v;
double a;
double b;
double tmp;
double s;
double result;
s = 1;
if (n < 0) {
n = -n;
if (n % 2 != 0)
s = -1;
}
if (n == 0) {
result = piY0(x);
return result;
}
if (n == 1) {
result = s * piY1(x);
return result;
}
a = piY0(x);
b = piY1(x);
for (i = 1; i <= n - 1; i++) {
tmp = b;
b = 2 * i / x * b - a;
a = tmp;
}
result = s * b;
return result;
#else
return yn(n, v);
#endif
}
double randomn(double dv, double sv) {
static bool agen = false;
double s = 2., v0 = 0., v1 = 0.;
if (agen) {
agen = false;
v1 = v1 * sqrt(-2 * log(s) / s);
return v1 * sv + dv;
}
while (s > 1. || s == 0.) {
v0 = randomd();
v1 = randomd();
s = v0*v0 + v1*v1;
}
v0 = v0 * sqrt(-2 * log(s) / s);
return v0 * sv + dv;
}
double randomd() {
return (double) rand() / RAND_MAX * 2. - 1.;
}