General Purpose library for Freestanding C++ and POSIX systems
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

255 linhas
5.6 KiB

  1. #pragma once
  2. #include "gp/algorithms/repeat.hpp"
  3. #include "gp/math/details/math_definitions.hpp"
  4. #include <limits>
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. namespace gp{
  8. namespace math{
  9. template<>
  10. constexpr float pi<float> = 3.1415926535897932384626433832795028841971693993751058209749445923078164062;
  11. template<>
  12. constexpr double pi<double> = 3.1415926535897932384626433832795028841971693993751058209749445923078164062L;
  13. template<>
  14. constexpr float abs<float>(float value) {
  15. static_assert(sizeof(float) == 4, "bad float size");
  16. union {
  17. float fp;
  18. uint32_t ab;
  19. } p;
  20. p.fp = value;
  21. p.ab &= 0x7fFFffFF;
  22. return p.fp;
  23. }
  24. template<>
  25. constexpr double abs<double>(double value) {
  26. static_assert(sizeof(double) == 8, "bad double size");
  27. union {
  28. double fp;
  29. uint64_t ab;
  30. } p;
  31. p.fp = value;
  32. p.ab &= 0x7fFFffFFffFFffFF;
  33. return p.fp;
  34. }
  35. template<typename T>
  36. T floor(T);
  37. template<>
  38. constexpr float floor<float>(float value) {
  39. static_assert(sizeof(float) == 4, "bad float size");
  40. if(
  41. value >= 16777216
  42. || value <= std::numeric_limits<int32_t>::min()
  43. || value != value
  44. ) {
  45. return value;
  46. }
  47. int32_t ret = value;
  48. float ret_d = ret;
  49. if(value == ret_d || value >= 0) {
  50. return ret;
  51. } else {
  52. return ret-1;
  53. }
  54. }
  55. template<>
  56. constexpr double floor<double>(double value) {
  57. static_assert(sizeof(double) == 8, "bad double size");
  58. if(
  59. value >= 9007199254740992
  60. || value <= std::numeric_limits<int64_t>::min()
  61. || value != value
  62. ) {
  63. return value;
  64. }
  65. int64_t ret = value;
  66. double ret_d = ret;
  67. if(value == ret_d || value >= 0) {
  68. return ret;
  69. } else {
  70. return ret-1;
  71. }
  72. }
  73. template<>
  74. constexpr float sign<float>(float value) {
  75. static_assert(sizeof(float) == 4, "bad float size");
  76. if(!value) return 0;
  77. union {
  78. float fp;
  79. uint32_t ab;
  80. } p;
  81. p.fp = value;
  82. p.ab &= 0x7fFFffFF;
  83. return value/p.fp;
  84. }
  85. template<>
  86. constexpr double sign<double>(double value) {
  87. static_assert(sizeof(double) == 8, "bad double size");
  88. if(!value) return 0;
  89. union {
  90. double fp;
  91. uint64_t ab;
  92. } p;
  93. p.fp = value;
  94. p.ab &= 0x7fFFffFFffFFffFF;
  95. return value/p.fp;
  96. }
  97. /**
  98. * @brief Calculate the sin of a value using Taylor's method
  99. *
  100. * @tparam steps The number of steps to do at the maximum
  101. * @tparam T the type of value and the return type expected
  102. * @tparam accuracy the maximum accuracy to shoot for (early stopping)
  103. * @param value The value to calculate the sin of. Works better for values close to 0.
  104. * @return T the sin of the value (the sign may be off idk I don't remember)
  105. */
  106. template<size_t steps, typename T, size_t accuracy = 1000000>
  107. constexpr T sin_taylor(T value) {
  108. const T acc = T{1}/T{accuracy};
  109. T B = value;
  110. T C = 1;
  111. T ret = B/C;
  112. for(size_t i = 1; (i < steps) && (abs<>(B/C) > acc); ++i) {
  113. B *= -1*value*value;
  114. C *= 2*i*(2*i+1);
  115. ret += B/C;
  116. }
  117. return ret;
  118. }
  119. /**
  120. * @brief General purpose sin function
  121. *
  122. * @param v
  123. * @return float
  124. */
  125. constexpr inline float sin(float v) {
  126. // limit the range between -pi and +pi
  127. v += pi<float>;
  128. v = v - 2*pi<float>*floor(v/(2*pi<float>));
  129. v -= pi<float>;
  130. float s = sign(v);
  131. v *= s;
  132. // use taylor's method on the value
  133. return sin_taylor<10>(v)*s;
  134. }
  135. /**
  136. * @brief General purpose sin function
  137. *
  138. * @param v
  139. * @return double
  140. */
  141. constexpr inline double sin(double v) {
  142. v += pi<double>;
  143. v = v - 2*pi<double>*floor(v/(2*pi<double>));
  144. v -= pi<double>;
  145. float s = sign(v);
  146. v *= s;
  147. return sin_taylor<10>(v)*s;
  148. }
  149. // TODO: replace with an actual implementation
  150. constexpr inline float cos(float v) {
  151. return sin(v+pi<float>/2);
  152. }
  153. // TODO: replace with an actual implementation
  154. constexpr inline double cos(double v) {
  155. return sin(v+pi<double>/2);
  156. }
  157. // TODO: replace with an actual implementation
  158. constexpr inline float tan(float v) {
  159. return sin(v)/cos(v);
  160. }
  161. // TODO: replace with an actual implementation
  162. constexpr inline double tan(double v) {
  163. return sin(v)/cos(v);
  164. }
  165. /**
  166. * @brief Quake isqrt (x) -> 1/sqrt(x)
  167. *
  168. * @tparam cycles the number of newton method cycles to apply
  169. * @param v the value to apply the function on
  170. * @return float \f$\frac{1}{\sqrt{v}}\f$
  171. */
  172. template<size_t cycles = 5>
  173. float isqrt(float v) {
  174. int32_t i;
  175. float x2, y;
  176. constexpr float threehalfs = 1.5F;
  177. x2 = v * 0.5F;
  178. y = v;
  179. i = * ( int32_t * ) &y;
  180. i = 0x5F375A86 - ( i >> 1 );
  181. y = * ( float * ) &i;
  182. gp::repeat(cycles, [&](){
  183. y = y * ( threehalfs - ( x2 * y * y ) );
  184. });
  185. return y;
  186. }
  187. /**
  188. * @brief Quake isqrt (x) -> 1/sqrt(x) but for doubles
  189. *
  190. * @tparam cycles the number of newton method cycles to apply
  191. * @param v the value to apply the function on
  192. * @return double \f$\frac{1}{\sqrt{v}}\f$
  193. */
  194. template<size_t cycles = 5>
  195. double isqrt(double v) {
  196. int64_t i;
  197. double x2, y;
  198. constexpr double threehalfs = 1.5F;
  199. x2 = v * 0.5F;
  200. y = v;
  201. i = * ( int64_t * ) &y;
  202. i = 0x5FE6EB50C7B537A9 - ( i >> 1 );
  203. y = * ( double * ) &i;
  204. gp::repeat(cycles, [&](){
  205. y = y * ( threehalfs - ( x2 * y * y ) );
  206. });
  207. return y;
  208. }
  209. /**
  210. * @brief A faster version of the Quake isqrt (actually the same but with defined cycles)
  211. *
  212. * @param v
  213. * @return float
  214. */
  215. inline float fast_isqrt(float v) {return isqrt<1>(v);}
  216. /**
  217. * @brief A faster version of the Quake isqrt (actually the same but with defined cycles)
  218. *
  219. * @param v
  220. * @return double
  221. */
  222. inline double fast_isqrt(double v) {return isqrt<1>(v);}
  223. }
  224. }