General Purpose library for Freestanding C++ and POSIX systems
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
5.4 KiB

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