//! \~\file pimathbase.h //! \~\ingroup Math //! \~\brief //! \~english Basic mathematical constants and helper algorithms //! \~russian Базовые математические константы и вспомогательные алгоритмы /* PIP - Platform Independent Primitives Basic mathematical functions and defines Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 . */ #ifndef PIMATHBASE_H #define PIMATHBASE_H #include "piinit.h" #include "pipair.h" #include "pivector.h" #ifdef QNX # undef PIP_MATH_J0 # undef PIP_MATH_J1 # undef PIP_MATH_JN # undef PIP_MATH_Y0 # undef PIP_MATH_Y1 # undef PIP_MATH_YN # include #else # include #endif //! \name Mathematical constants //! \{ //! \~english Natural logarithm of 2 //! \~russian Натуральный логарифм 2 #ifndef M_LN2 # define M_LN2 0.69314718055994530942 #endif //! \~english Natural logarithm of 10 //! \~russian Натуральный логарифм 10 #ifndef M_LN10 # define M_LN10 2.30258509299404568402 #endif //! \~english Square root of 2 //! \~russian Квадратный корень из 2 #ifndef M_SQRT2 # define M_SQRT2 1.41421356237309514547 #endif //! \~english Square root of 3 //! \~russian Квадратный корень из 3 #ifndef M_SQRT3 # define M_SQRT3 1.73205080756887719318 #endif //! \~english 1 divided by square root of 2 //! \~russian 1 делить на квадратный корень из 2 #ifndef M_1_SQRT2 # define M_1_SQRT2 0.70710678118654746172 #endif //! \~english 1 divided by square root of 3 //! \~russian 1 делить на квадратный корень из 3 #ifndef M_1_SQRT3 # define M_1_SQRT3 0.57735026918962584208 #endif //! \~english Pi constant //! \~russian Число Пи #ifndef M_PI # define M_PI 3.141592653589793238462643383280 #endif //! \~english 2 times Pi //! \~russian 2 times Пи #ifndef M_2PI # define M_2PI 6.283185307179586476925286766559 #endif //! \~english Pi divided by 3 //! \~russian Пи делить на 3 #ifndef M_PI_3 # define M_PI_3 1.04719755119659774615 #endif //! \~english 2 times Pi divided by 3 //! \~russian 2 times Пи делить на 3 #ifndef M_2PI_3 # define M_2PI_3 2.0943951023931954923 #endif //! \~english 180 divided by Pi (degrees to radians conversion factor) //! \~russian 180 делить на Пи (коэффициент преобразования градусов в радианы) #ifndef M_180_PI # define M_180_PI 57.2957795130823208768 #endif //! \~english Pi divided by 180 (radians to degrees conversion factor) //! \~russian Пи делить на 180 (коэффициент преобразования радианов в градусы) #ifndef M_PI_180 # define M_PI_180 1.74532925199432957692e-2 #endif //! \~english Square root of Pi //! \~russian Квадратный корень из Пи #ifndef M_SQRT_PI # define M_SQRT_PI 1.772453850905516027298167483341 #endif //! \~english Euler's number //! \~russian Число Эйлера #ifndef M_E # define M_E 2.7182818284590452353602874713527 #endif //! \~english Speed of light in vacuum //! \~russian Скорость света в вакууме #ifndef M_LIGHT_SPEED # define M_LIGHT_SPEED 2.99792458e+8 #endif //! \~english Relative gas constant //! \~russian Газовая постоянная #ifndef M_RELATIVE_CONST # define M_RELATIVE_CONST -4.442807633e-10; #endif //! \~english Gravitational constant //! \~russian Гравитационная постоянная #ifndef M_GRAVITY_CONST # define M_GRAVITY_CONST 398600.4418e9; #endif //! \} //! \~english Multiplicative factor for converting degrees to radians. //! \~russian Множитель для перевода градусов в радианы. const double deg2rad = M_PI_180; //! \~english Multiplicative factor for converting radians to degrees. //! \~russian Множитель для перевода радиан в градусы. const double rad2deg = M_180_PI; // clang-format off //! \~english Returns the sign of a floating-point value. //! \~russian Возвращает знак вещественного значения. inline int sign(const float & x) {return (x < 0.f) ? -1 : (x > 0.f ? 1 : 0);} //! \~english Returns the sign of a floating-point value. //! \~russian Возвращает знак вещественного значения. inline int sign(const double & x) {return (x < 0. ) ? -1 : (x > 0. ? 1 : 0);} //! \~english Returns the sign of a floating-point value. //! \~russian Возвращает знак вещественного значения. inline int sign(const ldouble & x) {return (x < 0.L) ? -1 : (x > 0.L ? 1 : 0);} //! \~english Returns `2` raised to integer power \a p. //! \~russian Возвращает `2` в целой степени \a p. inline int pow2 (const int p ) {return 1 << p;} //! \~english Returns `10` raised to the specified power. //! \~russian Возвращает `10` в указанной степени. inline float pow10(const float & e) {return powf(10.f, e);} //! \~english Returns `10` raised to the specified power. //! \~russian Возвращает `10` в указанной степени. inline double pow10(const double & e) {return pow (10. , e);} //! \~english Returns `10` raised to the specified power. //! \~russian Возвращает `10` в указанной степени. inline ldouble pow10(const ldouble & e) {return powl(10.L, e);} // clang-format on //! \~english Returns normalized sinc, `sin(pi*x)/(pi*x)`. //! \~russian Возвращает нормированную функцию sinc, `sin(pi*x)/(pi*x)`. inline double sinc(const double & v) { if (v == 0.) return 1.; double t = M_PI * v; return sin(t) / t; } //! \name Bessel functions //! \{ //! //! \~english Bessel function of the first kind of order 0 //! \~russian Функция Бесселя первого рода порядка 0 //! \details //! \~english Bessel function of the first kind J0(x), solution to Bessel's differential equation //! \~russian Функция Бесселя первого рода J0(x), решение уравнения Бесселя //! \~\sa piJ1(), piJn() PIP_EXPORT double piJ0(const double & v); //! \~english Bessel function of the first kind of order 1 //! \~russian Функция Бесселя первого рода порядка 1 //! \details //! \~english Bessel function of the first kind J1(x), solution to Bessel's differential equation //! \~russian Функция Бесселя первого рода J1(x), решение уравнения Бесселя //! \~\sa piJ0(), piJn() PIP_EXPORT double piJ1(const double & v); //! \~english Bessel function of the first kind of order n //! \~russian Функция Бесселя первого рода порядка n //! \details //! \~english Bessel function of the first kind Jn(n, x), solution to Bessel's differential equation //! \~russian Функция Бесселя первого рода Jn(n, x), решение уравнения Бесселя //! \~\sa piJ0(), piJ1() PIP_EXPORT double piJn(int n, const double & v); //! \~english Bessel function of the second kind of order 0 //! \~russian Функция Бесселя второго рода порядка 0 //! \details //! \~english Bessel function of the second kind Y0(x), also known as Neumann function //! \~russian Функция Бесселя второго рода Y0(x), также известная как функция Неймана //! \~\sa piY1(), piYn() PIP_EXPORT double piY0(const double & v); //! \~english Bessel function of the second kind of order 1 //! \~russian Функция Бесселя второго рода порядка 1 //! \details //! \~english Bessel function of the second kind Y1(x), also known as Neumann function //! \~russian Функция Бесселя второго рода Y1(x), также известная как функция Неймана //! \~\sa piY0(), piYn() PIP_EXPORT double piY1(const double & v); //! \~english Bessel function of the second kind of order n //! \~russian Функция Бесселя второго рода порядка n //! \details //! \~english Bessel function of the second kind Yn(n, x), also known as Neumann function //! \~russian Функция Бесселя второго рода Yn(n, x), также известная как функция Неймана //! \~\sa piY0(), piY1() PIP_EXPORT double piYn(int n, const double & v); //! \} // clang-format off //! \~english Converts degrees to radians. //! \~russian Преобразует градусы в радианы. inline constexpr float toRad(float deg) {return deg * M_PI_180;} //! \~english Converts degrees to radians. //! \~russian Преобразует градусы в радианы. inline constexpr double toRad(double deg) {return deg * M_PI_180;} //! \~english Converts degrees to radians. //! \~russian Преобразует градусы в радианы. inline constexpr ldouble toRad(ldouble deg) {return deg * M_PI_180;} //! \~english Converts radians to degrees. //! \~russian Преобразует радианы в градусы. inline constexpr float toDeg(float rad) {return rad * M_180_PI;} //! \~english Converts radians to degrees. //! \~russian Преобразует радианы в градусы. inline constexpr double toDeg(double rad) {return rad * M_180_PI;} //! \~english Converts radians to degrees. //! \~russian Преобразует радианы в градусы. inline constexpr ldouble toDeg(ldouble rad) {return rad * M_180_PI;} // clang-format on //! \~english Returns square of a value. //! \~russian Возвращает квадрат значения. template inline constexpr T sqr(const T & v) { return v * v; } //! \~english Converts a power ratio to decibels. //! \~russian Преобразует отношение мощностей в децибелы. template inline constexpr T toDb(T val) { return T(10.) * std::log10(val); } //! \~english Converts decibels to a linear power ratio. //! \~russian Преобразует децибелы в линейное отношение мощностей. template inline constexpr T fromDb(T val) { return std::pow(T(10.), val / T(10.)); } //! \~english Returns a pseudo-random value in the range `[-1; 1]`. //! \~russian Возвращает псевдослучайное значение в диапазоне `[-1; 1]`. PIP_EXPORT double randomd(); //! \~english Returns a normally distributed pseudo-random value with mean \a dv and deviation \a sv. //! \~russian Возвращает нормально распределенное псевдослучайное значение со средним \a dv и отклонением \a sv. PIP_EXPORT double randomn(double dv = 0., double sv = 1.); //! \~english Returns vector with absolute values of each element //! \~russian Возвращает вектор с абсолютными значениями каждого элемента template inline PIVector piAbs(const PIVector & v) { PIVector result; result.resize(v.size()); for (uint i = 0; i < v.size(); i++) result[i] = piAbs(v[i]); return result; } //! \~english Normalizes an angle to the `[0; 360]` degree range in place. //! \~russian Нормализует угол к диапазону `[0; 360]` градусов на месте. template void normalizeAngleDeg360(T & a) { while (a < 0.) a += 360.; while (a > 360.) a -= 360.; } //! \~english Returns an angle normalized to the `[0; 360]` degree range. //! \~russian Возвращает угол, нормализованный к диапазону `[0; 360]` градусов. template double normalizedAngleDeg360(T a) { normalizeAngleDeg360(a); return a; } //! \~english Normalizes an angle to the `[-180; 180]` degree range in place. //! \~russian Нормализует угол к диапазону `[-180; 180]` градусов на месте. template void normalizeAngleDeg180(T & a) { while (a < -180.) a += 360.; while (a > 180.) a -= 360.; } //! \~english Returns an angle normalized to the `[-180; 180]` degree range. //! \~russian Возвращает угол, нормализованный к диапазону `[-180; 180]` градусов. template double normalizedAngleDeg180(T a) { normalizeAngleDeg180(a); return a; } //! \~english Fits a linear model `y = a*x + b` with ordinary least squares. //! \~russian Аппроксимирует линейную модель `y = a*x + b` методом наименьших квадратов. //! \~\details //! \~english Returns \c false when fewer than two sample pairs are provided. //! \~russian Возвращает \c false, если передано меньше двух пар значений. template bool OLS_Linear(const PIVector> & input, T * out_a, T * out_b) { static_assert(std::is_arithmetic::value, "Type must be arithmetic"); if (input.size_s() < 2) return false; int n = input.size_s(); T a_t0 = T(), a_t1 = T(), a_t2 = T(), a_t3 = T(), a_t4 = T(), a = T(), b = T(); for (int i = 0; i < n; ++i) { const PIPair & cv(input[i]); a_t0 += cv.first * cv.second; a_t1 += cv.first; a_t2 += cv.second; a_t3 += cv.first * cv.first; } a_t4 = n * a_t3 - a_t1 * a_t1; if (a_t4 != T()) a = (n * a_t0 - a_t1 * a_t2) / a_t4; b = (a_t2 - a * a_t1) / n; if (out_a != 0) *out_a = a; if (out_b != 0) *out_b = b; return true; } //! \~english Fits a weighted linear model `y = a*x + b`. //! \~russian Аппроксимирует взвешенную линейную модель `y = a*x + b`. //! \~\details //! \~english Returns \c false when the sample is too small or the weights vector has a different size. //! \~russian Возвращает \c false, если выборка слишком мала или размер вектора весов не совпадает. template bool WLS_Linear(const PIVector> & input, const PIVector & weights, T * out_a, T * out_b) { static_assert(std::is_arithmetic::value, "Type must be arithmetic"); if (input.size_s() < 2) return false; if (input.size_s() != weights.size_s()) return false; int n = input.size_s(); T a_t0 = T(), a_t1 = T(), a_t2 = T(), a_t3 = T(), a_t4 = T(), a_n = T(), a = T(), b = T(); for (int i = 0; i < n; ++i) { T cp = weights[i]; const PIPair & cv(input[i]); a_t0 += cv.first * cv.second * cp; a_t1 += cv.first * cp; a_t2 += cv.second * cp; a_t3 += cv.first * cv.first * cp; a_n += cp; } a_t4 = a_n * a_t3 - a_t1 * a_t1; if (a_t4 != T()) a = (a_n * a_t0 - a_t1 * a_t2) / a_t4; b = (a_t2 - a * a_t1) / a_n; if (out_a != 0) *out_a = a; if (out_b != 0) *out_b = b; return true; } #endif // PIMATHBASE_H