Files
pip/libs/main/math/pimathbase.h
2026-03-12 14:46:57 +03:00

402 lines
15 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \~\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 <http://www.gnu.org/licenses/>.
*/
#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 <math.h>
#else
# include <cmath>
#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<typename T>
inline constexpr T sqr(const T & v) {
return v * v;
}
//! \~english Converts a power ratio to decibels.
//! \~russian Преобразует отношение мощностей в децибелы.
template<typename T>
inline constexpr T toDb(T val) {
return T(10.) * std::log10(val);
}
//! \~english Converts decibels to a linear power ratio.
//! \~russian Преобразует децибелы в линейное отношение мощностей.
template<typename T>
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<typename T>
inline PIVector<T> piAbs(const PIVector<T> & v) {
PIVector<T> result;
result.resize(v.size());
for (uint i = 0; i < v.size(); i++)
result[i] = piAbs<T>(v[i]);
return result;
}
//! \~english Normalizes an angle to the `[0; 360]` degree range in place.
//! \~russian Нормализует угол к диапазону `[0; 360]` градусов на месте.
template<typename T>
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<typename T>
double normalizedAngleDeg360(T a) {
normalizeAngleDeg360(a);
return a;
}
//! \~english Normalizes an angle to the `[-180; 180]` degree range in place.
//! \~russian Нормализует угол к диапазону `[-180; 180]` градусов на месте.
template<typename T>
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<typename T>
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<typename T>
bool OLS_Linear(const PIVector<PIPair<T, T>> & input, T * out_a, T * out_b) {
static_assert(std::is_arithmetic<T>::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<T, T> & 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<typename T>
bool WLS_Linear(const PIVector<PIPair<T, T>> & input, const PIVector<T> & weights, T * out_a, T * out_b) {
static_assert(std::is_arithmetic<T>::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<T, T> & 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