QFNumber.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2020.01.10
  7. #pragma once
  8. #include <Mathematics/Logger.h>
  9. // Class QFNumber is an implementation for quadratic fields with N >= 1
  10. // square root terms. The theory and details are provided in
  11. // https://www.geometrictools.com/Documentation/QuadraticFields.pdf
  12. // Enable this macro if you want the logging system to trap when arithmetic
  13. // operations are performed on two quadratic elements that do not share the
  14. // same value d
  15. #define GTE_ASSERT_ON_QFNUMBER_MISMATCHED_D
  16. namespace WwiseGTE
  17. {
  18. // Arithmetic for quadratic fields with N >= 2 square root terms. The
  19. // d-term is rational and the x-coefficients are elements in a quadratic
  20. // field with N-1 >= 1 square root terms.
  21. template <typename T, size_t N>
  22. class QFNumber
  23. {
  24. public:
  25. // The quadratic field numbers is x[0] + x[1] * sqrt(d).
  26. std::array<QFNumber<T, N - 1>, 2> x;
  27. T d;
  28. // Create z = 0 + 0 * sqrt(0), where the 0 coefficients are quadratic
  29. // field elements with N-1 d-terms all set to 0 and x-coefficients all
  30. // set to 0.
  31. QFNumber()
  32. :
  33. d(0)
  34. {
  35. static_assert(N >= 2, "Invalid number of root arguments.");
  36. }
  37. // Create z = 0 + 0 * sqrt(d), where the 0 coefficients are quadratic
  38. // field elements with N-1 d-terms all set to 0 and x-coefficients all
  39. // set to 0.
  40. explicit QFNumber(T const& inD)
  41. :
  42. d(inD)
  43. {
  44. static_assert(N >= 2, "Invalid number of root arguments.");
  45. }
  46. // Create z = x0 + x1 * sqrt(d), where the x-coefficients are
  47. // quadratic field elements with N-1 d-terms.
  48. QFNumber(QFNumber<T, N - 1> const& x0, QFNumber<T, N - 1> const& x1, T const& inD)
  49. :
  50. x{ x0, x1 },
  51. d(inD)
  52. {
  53. static_assert(N >= 2, "Invalid number of root arguments.");
  54. }
  55. // Create z = inX[0] + inX[1] * sqrt(inD), where the x-coefficients are
  56. // quadratic field elements with N-1 d-terms.
  57. QFNumber(std::array<QFNumber<T, N - 1>, 2> const& inX, T const& inD)
  58. :
  59. x(inX),
  60. d(inD)
  61. {
  62. static_assert(N >= 2, "Invalid number of root arguments.");
  63. }
  64. };
  65. // Arithmetic for quadratic fields with 1 square root term.
  66. template <typename T>
  67. class QFNumber<T, 1>
  68. {
  69. public:
  70. // The quadratic field number is x[0] + x[1] * sqrt(d).
  71. std::array<T, 2> x;
  72. T d;
  73. // Create z = 0. You can defer the setting of d until later.
  74. QFNumber()
  75. :
  76. x{ static_cast<T>(0), static_cast<T>(0) },
  77. d(static_cast<T>(0))
  78. {
  79. }
  80. // Create z = 0 + 0 * sqrt(d) = 0.
  81. explicit QFNumber(T const& inD)
  82. :
  83. x{ static_cast<T>(0), static_cast<T>(0) },
  84. d(inD)
  85. {
  86. }
  87. // Create z = x0 + x1 * sqrt(d).
  88. QFNumber(T const& x0, T const& x1, T const& inD)
  89. :
  90. x{ x0, x1 },
  91. d(inD)
  92. {
  93. }
  94. // Create z = inX[0] + inX[1] * sqrt(d).
  95. QFNumber(std::array<T, 2> const& inX, T const& inD)
  96. :
  97. x(inX),
  98. d(inD)
  99. {
  100. }
  101. };
  102. // Unary operations.
  103. template <typename T, size_t N>
  104. QFNumber<T, N> operator+(QFNumber<T, N> const& q)
  105. {
  106. static_assert(N >= 1, "Invalid number of d-terms.");
  107. return q;
  108. }
  109. template <typename T, size_t N>
  110. QFNumber<T, N> operator-(QFNumber<T, N> const& q)
  111. {
  112. static_assert(N >= 1, "Invalid number of d-terms.");
  113. return QFNumber<T, N>(-q.x[0], -q.x[1], q.d);
  114. }
  115. // Arithmetic operations between elements of a quadratic field must occur
  116. // only when the d-values are the same. To trap mismatches, read the
  117. // comments at the beginning of this file.
  118. template <typename T, size_t N>
  119. QFNumber<T, N> operator+(QFNumber<T, N> const& q0, QFNumber<T, N> const& q1)
  120. {
  121. #if defined(GTE_ASSERT_ON_QFNUMBER_MISMATCHED_D)
  122. LogAssert(q0.d == q1.d, "Mismatched d-value.");
  123. #endif
  124. return QFNumber<T, N>(q0.x[0] + q1.x[0], q0.x[1] + q1.x[1], q0.d);
  125. }
  126. template <typename T, size_t N>
  127. QFNumber<T, N> operator+(QFNumber<T, N> const& q, T const& s)
  128. {
  129. return QFNumber<T, N>(q.x[0] + s, q.x[1], q.d);
  130. }
  131. template <typename T, size_t N>
  132. QFNumber<T, N> operator+(T const& s, QFNumber<T, N> const& q)
  133. {
  134. return QFNumber<T, N>(s + q.x[0], q.x[1], q.d);
  135. }
  136. template <typename T, size_t N>
  137. QFNumber<T, N> operator-(QFNumber<T, N> const& q0, QFNumber<T, N> const& q1)
  138. {
  139. #if defined(GTE_ASSERT_ON_QFNUMBER_MISMATCHED_D)
  140. LogAssert(q0.d == q1.d, "Mismatched d-value.");
  141. #endif
  142. return QFNumber<T, N>(q0.x[0] - q1.x[0], q0.x[1] - q1.x[1], q0.d);
  143. }
  144. template <typename T, size_t N>
  145. QFNumber<T, N> operator-(QFNumber<T, N> const& q, T const& s)
  146. {
  147. return QFNumber<T, N>(q.x[0] - s, q.x[1], q.d);
  148. }
  149. template <typename T, size_t N>
  150. QFNumber<T, N> operator-(T const& s, QFNumber<T, N> const& q)
  151. {
  152. return QFNumber<T, N>(s - q.x[0], -q.x[1], q.d);
  153. }
  154. template <typename T, size_t N>
  155. QFNumber<T, N> operator*(QFNumber<T, N> const& q0, QFNumber<T, N> const& q1)
  156. {
  157. #if defined(GTE_ASSERT_ON_QFNUMBER_MISMATCHED_D)
  158. LogAssert(q0.d == q1.d, "Mismatched d-value.");
  159. #endif
  160. return QFNumber<T, N>(
  161. q0.x[0] * q1.x[0] + q0.x[1] * q1.x[1] * q0.d,
  162. q0.x[0] * q1.x[1] + q0.x[1] * q1.x[0],
  163. q0.d);
  164. }
  165. template <typename T, size_t N>
  166. QFNumber<T, N> operator*(QFNumber<T, N> const& q, T const& s)
  167. {
  168. return QFNumber<T, N>(q.x[0] * s, q.x[1] * s, q.d);
  169. }
  170. template <typename T, size_t N>
  171. QFNumber<T, N> operator*(T const& s, QFNumber<T, N> const& q)
  172. {
  173. return QFNumber<T, N>(s * q.x[0], s * q.x[1], q.d);
  174. }
  175. template <typename T, size_t N>
  176. QFNumber<T, N> operator/(QFNumber<T, N> const& q0, QFNumber<T, N> const& q1)
  177. {
  178. #if defined(GTE_ASSERT_ON_QFNUMBER_MISMATCHED_D)
  179. LogAssert(q0.d == q1.d, "Mismatched d-value.");
  180. #endif
  181. auto denom = q1.x[0] * q1.x[0] - q1.x[1] * q1.x[1] * q0.d;
  182. auto numer0 = q0.x[0] * q1.x[0] - q0.x[1] * q1.x[1] * q0.d;
  183. auto numer1 = q0.x[1] * q1.x[0] - q0.x[0] * q1.x[1];
  184. return QFNumber<T, N>(numer0 / denom, numer1 / denom, q0.d);
  185. }
  186. template <typename T, size_t N>
  187. QFNumber<T, N> operator/(QFNumber<T, N> const& q, T const& s)
  188. {
  189. return QFNumber<T, N>(q.x[0] / s, q.x[1] / s, q.d);
  190. }
  191. template <typename T, size_t N>
  192. QFNumber<T, N> operator/(T const& s, QFNumber<T, N> const& q)
  193. {
  194. auto denom = q.x[0] * q.x[0] - q.x[1] * q.x[1] * q.d;
  195. auto x0 = (s * q.x[0]) / denom;
  196. auto x1 = -(s * q.x[1]) / denom;
  197. return QFNumber<T, N>(x0, x1, q.d);
  198. }
  199. // Arithmetic updates between elements of a quadratic field must occur
  200. // only when the d-values are the same. To trap mismatches, read the
  201. // comments at the beginning of this file.
  202. template <typename T, size_t N>
  203. QFNumber<T, N>& operator+=(QFNumber<T, N>& q0, QFNumber<T, N> const& q1)
  204. {
  205. #if defined(GTE_ASSERT_ON_QFNUMBER_MISMATCHED_D)
  206. LogAssert(q0.d == q1.d, "Mismatched d-value.");
  207. #endif
  208. q0.x[0] += q1.x[0];
  209. q0.x[1] += q1.x[1];
  210. return q0;
  211. }
  212. template <typename T, size_t N>
  213. QFNumber<T, N>& operator+=(QFNumber<T, N>& q, T const& s)
  214. {
  215. q.x[0] += s;
  216. return q;
  217. }
  218. template <typename T, size_t N>
  219. QFNumber<T, N>& operator-=(QFNumber<T, N>& q0, QFNumber<T, N> const& q1)
  220. {
  221. #if defined(GTE_ASSERT_ON_QFNUMBER_MISMATCHED_D)
  222. LogAssert(q0.d == q1.d, "Mismatched d-value.");
  223. #endif
  224. q0.x[0] -= q1.x[0];
  225. q0.x[1] -= q1.x[1];
  226. return q0;
  227. }
  228. template <typename T, size_t N>
  229. QFNumber<T, N>& operator-=(QFNumber<T, N>& q, T const& s)
  230. {
  231. q.x[0] -= s;
  232. return q;
  233. }
  234. template <typename T, size_t N>
  235. QFNumber<T, N>& operator*=(QFNumber<T, N>& q0, QFNumber<T, N> const& q1)
  236. {
  237. #if defined(GTE_ASSERT_ON_QFNUMBER_MISMATCHED_D)
  238. LogAssert(q0.d == q1.d, "Mismatched d-value.");
  239. #endif
  240. auto x0 = q0.x[0] * q1.x[0] + q0.x[1] * q1.x[1] * q0.d;
  241. auto x1 = q0.x[0] * q1.x[1] + q0.x[1] * q1.x[0];
  242. q0.x[0] = x0;
  243. q0.x[1] = x1;
  244. return q0;
  245. }
  246. template <typename T, size_t N>
  247. QFNumber<T, N>& operator*=(QFNumber<T, N>& q, T const& s)
  248. {
  249. q.x[0] *= s;
  250. q.x[1] *= s;
  251. return q;
  252. }
  253. template <typename T, size_t N>
  254. QFNumber<T, N>& operator/=(QFNumber<T, N>& q0, QFNumber<T, N> const& q1)
  255. {
  256. #if defined(GTE_ASSERT_ON_QFNUMBER_MISMATCHED_D)
  257. LogAssert(q0.d == q1.d, "Mismatched d-value.");
  258. #endif
  259. auto denom = q1.x[0] * q1.x[0] - q1.x[1] * q1.x[1] * q0.d;
  260. auto numer0 = q0.x[0] * q1.x[0] - q0.x[1] * q1.x[1] * q0.d;
  261. auto numer1 = q0.x[1] * q1.x[0] - q0.x[0] * q1.x[1];
  262. q0.x[0] = numer0 / denom;
  263. q0.x[1] = numer1 / denom;
  264. return q0;
  265. }
  266. template <typename T, size_t N>
  267. QFNumber<T, N>& operator/=(QFNumber<T, N>& q, T const& s)
  268. {
  269. q.x[0] /= s;
  270. q.x[1] /= s;
  271. return q;
  272. }
  273. // Comparisons between numbers of a quadratic field must occur only when
  274. // the d-values are the same. To trap mismatches, read the comments at
  275. // the beginning of this file.
  276. template <typename T, size_t N>
  277. bool operator==(QFNumber<T, N> const& q0, QFNumber<T, N> const& q1)
  278. {
  279. #if defined(GTE_ASSERT_ON_QFNUMBER_MISMATCHED_D)
  280. LogAssert(q0.d == q1.d, "Mismatched d-value.");
  281. #endif
  282. if (q0.d == T(0) || q0.x[1] == q1.x[1])
  283. {
  284. return q0.x[0] == q1.x[0];
  285. }
  286. else if (q0.x[1] > q1.x[1])
  287. {
  288. if (q0.x[0] >= q1.x[0])
  289. {
  290. return false;
  291. }
  292. else // q0.x[0] < q1.x[0]
  293. {
  294. auto diff = q0 - q1;
  295. return diff.x[0] * diff.x[0] == diff.x[1] * diff.x[1] * diff.d;
  296. }
  297. }
  298. else // q0.x[1] < q1.x[1]
  299. {
  300. if (q0.x[0] <= q1.x[0])
  301. {
  302. return false;
  303. }
  304. else // q0.x[0] > q1.x[0]
  305. {
  306. auto diff = q0 - q1;
  307. return diff.x[0] * diff.x[0] == diff.x[1] * diff.x[1] * diff.d;
  308. }
  309. }
  310. }
  311. template <typename T, size_t N>
  312. bool operator!=(QFNumber<T, N> const& q0, QFNumber<T, N> const& q1)
  313. {
  314. return !operator==(q0, q1);
  315. }
  316. template <typename T, size_t N>
  317. bool operator<(QFNumber<T, N> const& q0, QFNumber<T, N> const& q1)
  318. {
  319. #if defined(GTE_ASSERT_ON_QFNUMBER_MISMATCHED_D)
  320. LogAssert(q0.d == q1.d, "Mismatched d-value.");
  321. #endif
  322. if (q0.d == T(0) || q0.x[1] == q1.x[1])
  323. {
  324. return q0.x[0] < q1.x[0];
  325. }
  326. else if (q0.x[1] > q1.x[1])
  327. {
  328. if (q0.x[0] >= q1.x[0])
  329. {
  330. return false;
  331. }
  332. else // q0.x[0] < q1.x[0]
  333. {
  334. auto diff = q0 - q1;
  335. return diff.x[0] * diff.x[0] > diff.x[1] * diff.x[1] * diff.d;
  336. }
  337. }
  338. else // q0.x[1] < q1.x[1]
  339. {
  340. if (q0.x[0] <= q1.x[0])
  341. {
  342. return true;
  343. }
  344. else // q0.x[0] > q1.x[0]
  345. {
  346. auto diff = q0 - q1;
  347. return diff.x[0] * diff.x[0] < diff.x[1] * diff.x[1] * diff.d;
  348. }
  349. }
  350. }
  351. template <typename T, size_t N>
  352. bool operator>(QFNumber<T, N> const& q0, QFNumber<T, N> const& q1)
  353. {
  354. return operator<(q1, q0);
  355. }
  356. template <typename T, size_t N>
  357. bool operator<=(QFNumber<T, N> const& q0, QFNumber<T, N> const& q1)
  358. {
  359. return !operator<(q1, q0);
  360. }
  361. template <typename T, size_t N>
  362. bool operator>=(QFNumber<T, N> const& q0, QFNumber<T, N> const& q1)
  363. {
  364. return !operator<(q0, q1);
  365. }
  366. }