ymath.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #pragma once
  2. #include <util/system/yassert.h>
  3. #include <util/system/defaults.h>
  4. #include <cmath>
  5. #include <cfloat>
  6. #include <cstdlib>
  7. #include "typetraits.h"
  8. #include "utility.h"
  9. constexpr double PI = M_PI;
  10. constexpr double M_LOG2_10 = 3.32192809488736234787; // log2(10)
  11. constexpr double M_LN2_INV = M_LOG2E; // 1 / ln(2) == log2(e)
  12. /**
  13. * \returns Absolute value of the provided argument.
  14. */
  15. template <class T>
  16. constexpr T Abs(T value) {
  17. return std::abs(value);
  18. }
  19. /**
  20. * @returns Base 2 logarithm of the provided double
  21. * precision floating point value.
  22. */
  23. inline double Log2(double value) {
  24. return log(value) * M_LN2_INV;
  25. }
  26. /**
  27. * @returns Base 2 logarithm of the provided
  28. * floating point value.
  29. */
  30. inline float Log2(float value) {
  31. return logf(value) * static_cast<float>(M_LN2_INV);
  32. }
  33. /**
  34. * @returns Base 2 logarithm of the provided integral value.
  35. */
  36. template <class T>
  37. inline std::enable_if_t<std::is_integral<T>::value, double>
  38. Log2(T value) {
  39. return Log2(static_cast<double>(value));
  40. }
  41. /** Returns 2^x */
  42. double Exp2(double);
  43. float Exp2f(float);
  44. template <class T>
  45. static constexpr T Sqr(const T t) noexcept {
  46. return t * t;
  47. }
  48. inline double Sigmoid(double x) {
  49. return 1.0 / (1.0 + std::exp(-x));
  50. }
  51. inline float Sigmoid(float x) {
  52. return 1.0f / (1.0f + std::exp(-x));
  53. }
  54. static inline bool IsFinite(double f) {
  55. #if defined(isfinite)
  56. return isfinite(f);
  57. #elif defined(_win_)
  58. return _finite(f) != 0;
  59. #elif defined(_darwin_)
  60. return isfinite(f);
  61. #elif defined(__GNUC__)
  62. return __builtin_isfinite(f);
  63. #elif defined(_STLP_VENDOR_STD)
  64. return _STLP_VENDOR_STD::isfinite(f);
  65. #else
  66. return std::isfinite(f);
  67. #endif
  68. }
  69. static inline bool IsNan(double f) {
  70. #if defined(_win_)
  71. return _isnan(f) != 0;
  72. #else
  73. return std::isnan(f);
  74. #endif
  75. }
  76. inline bool IsValidFloat(double f) {
  77. return IsFinite(f) && !IsNan(f);
  78. }
  79. #ifdef _MSC_VER
  80. double Erf(double x);
  81. #else
  82. inline double Erf(double x) {
  83. return erf(x);
  84. }
  85. #endif
  86. /**
  87. * @returns Natural logarithm of the absolute value
  88. * of the gamma function of provided argument.
  89. */
  90. inline double LogGamma(double x) noexcept {
  91. #if defined(_glibc_)
  92. int sign;
  93. (void)sign;
  94. return lgamma_r(x, &sign);
  95. #elif defined(__GNUC__)
  96. return __builtin_lgamma(x);
  97. #elif defined(_unix_)
  98. return lgamma(x);
  99. #else
  100. extern double LogGammaImpl(double);
  101. return LogGammaImpl(x);
  102. #endif
  103. }
  104. /**
  105. * @returns x^n for integer n, n >= 0.
  106. */
  107. template <class T, class Int>
  108. T Power(T x, Int n) {
  109. static_assert(std::is_integral<Int>::value, "only integer powers are supported");
  110. Y_ASSERT(n >= 0);
  111. if (n == 0) {
  112. return T(1);
  113. }
  114. while ((n & 1) == 0) {
  115. x = x * x;
  116. n >>= 1;
  117. }
  118. T result = x;
  119. n >>= 1;
  120. while (n > 0) {
  121. x = x * x;
  122. if (n & 1) {
  123. result = result * x;
  124. }
  125. n >>= 1;
  126. }
  127. return result;
  128. }
  129. /**
  130. * Compares two floating point values and returns true if they are considered equal.
  131. * The two numbers are compared in a relative way, where the exactness is stronger
  132. * the smaller the numbers are.
  133. *
  134. * Note that comparing values where either one is 0.0 will not work.
  135. * The solution to this is to compare against values greater than or equal to 1.0.
  136. *
  137. * @code
  138. * // Instead of comparing with 0.0
  139. * FuzzyEquals(0.0, 1.0e-200); // This will return false
  140. * // Compare adding 1 to both values will fix the problem
  141. * FuzzyEquals(1 + 0.0, 1 + 1.0e-200); // This will return true
  142. * @endcode
  143. */
  144. inline bool FuzzyEquals(double p1, double p2, double eps = 1.0e-13) {
  145. return (Abs(p1 - p2) <= eps * Min(Abs(p1), Abs(p2)));
  146. }
  147. /**
  148. * @see FuzzyEquals(double, double, double)
  149. */
  150. inline bool FuzzyEquals(float p1, float p2, float eps = 1.0e-6) {
  151. return (Abs(p1 - p2) <= eps * Min(Abs(p1), Abs(p2)));
  152. }
  153. namespace NUtilMathPrivate {
  154. template <bool IsSigned>
  155. struct TCeilDivImpl {};
  156. template <>
  157. struct TCeilDivImpl<true> {
  158. template <class T>
  159. static inline constexpr T Do(T x, T y) noexcept {
  160. return x / y + (((x < 0) ^ (y > 0)) && (x % y));
  161. }
  162. };
  163. template <>
  164. struct TCeilDivImpl<false> {
  165. template <class T>
  166. static inline constexpr T Do(T x, T y) noexcept {
  167. auto quot = x / y;
  168. return (x % y) ? (quot + 1) : quot;
  169. }
  170. };
  171. } // namespace NUtilMathPrivate
  172. /**
  173. * @returns Equivalent to ceil((double) x / (double) y) but using only integer arithmetic operations
  174. */
  175. template <class T>
  176. inline T
  177. #if !defined(__NVCC__)
  178. constexpr
  179. #endif
  180. CeilDiv(T x, T y) noexcept {
  181. static_assert(std::is_integral<T>::value, "Integral type required.");
  182. Y_ASSERT(y != 0);
  183. return ::NUtilMathPrivate::TCeilDivImpl<std::is_signed<T>::value>::Do(x, y);
  184. }