FPInterval.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  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.1.2019.10.09
  7. #pragma once
  8. #include <Mathematics/Logger.h>
  9. #include <Mathematics/Math.h>
  10. #include <array>
  11. // The FPInterval [e0,e1] must satisfy e0 <= e1. Expose this define to trap
  12. // invalid construction where e0 > e1.
  13. #define GTE_THROW_ON_INVALID_INTERVAL
  14. namespace WwiseGTE
  15. {
  16. // The FPType must be 'float' or 'double'.
  17. template <typename FPType>
  18. class FPInterval
  19. {
  20. public:
  21. // Construction. This is the only way to create an interval. All such
  22. // intervals are immutable once created. The constructor
  23. // FPInterval(FPType) is used to create the degenerate interval [e,e].
  24. FPInterval()
  25. :
  26. mEndpoints{ static_cast<FPType>(0), static_cast<FPType>(0) }
  27. {
  28. static_assert(std::is_floating_point<FPType>::value, "Invalid type.");
  29. }
  30. FPInterval(FPInterval const& other)
  31. :
  32. mEndpoints(other.mEndpoints)
  33. {
  34. static_assert(std::is_floating_point<FPType>::value, "Invalid type.");
  35. }
  36. explicit FPInterval(FPType e)
  37. :
  38. mEndpoints{ e, e }
  39. {
  40. static_assert(std::is_floating_point<FPType>::value, "Invalid type.");
  41. }
  42. FPInterval(FPType e0, FPType e1)
  43. :
  44. mEndpoints{ e0, e1 }
  45. {
  46. static_assert(std::is_floating_point<FPType>::value, "Invalid type.");
  47. #if defined(GTE_THROW_ON_INVALID_INTERVAL)
  48. LogAssert(mEndpoints[0] <= mEndpoints[1], "Invalid FPInterval.");
  49. #endif
  50. }
  51. FPInterval(std::array<FPType, 2> const& endpoint)
  52. :
  53. mEndpoints(endpoint)
  54. {
  55. static_assert(std::is_floating_point<FPType>::value, "Invalid type.");
  56. #if defined(GTE_THROW_ON_INVALID_INTERVAL)
  57. LogAssert(mEndpoints[0] <= mEndpoints[1], "Invalid FPInterval.");
  58. #endif
  59. }
  60. FPInterval& operator=(FPInterval const& other)
  61. {
  62. static_assert(std::is_floating_point<FPType>::value, "Invalid type.");
  63. mEndpoints = other.mEndpoints;
  64. return *this;
  65. }
  66. // Member access. It is only possible to read the endpoints. You
  67. // cannot modify the endpoints outside the arithmetic operations.
  68. inline FPType operator[](size_t i) const
  69. {
  70. return mEndpoints[i];
  71. }
  72. inline std::array<FPType, 2> GetEndpoints() const
  73. {
  74. return mEndpoints;
  75. }
  76. // Arithmetic operations to compute intervals at the leaf nodes of
  77. // an expression tree. Such nodes correspond to the raw floating-point
  78. // variables of the expression. The non-class operators defined after
  79. // the class definition are used to compute intervals at the interior
  80. // nodes of the expression tree.
  81. inline static FPInterval Add(FPType u, FPType v)
  82. {
  83. FPInterval w;
  84. auto saveMode = std::fegetround();
  85. std::fesetround(FE_DOWNWARD);
  86. w.mEndpoints[0] = u + v;
  87. std::fesetround(FE_UPWARD);
  88. w.mEndpoints[1] = u + v;
  89. std::fesetround(saveMode);
  90. return w;
  91. }
  92. inline static FPInterval Sub(FPType u, FPType v)
  93. {
  94. FPInterval w;
  95. auto saveMode = std::fegetround();
  96. std::fesetround(FE_DOWNWARD);
  97. w.mEndpoints[0] = u - v;
  98. std::fesetround(FE_UPWARD);
  99. w.mEndpoints[1] = u - v;
  100. std::fesetround(saveMode);
  101. return w;
  102. }
  103. inline static FPInterval Mul(FPType u, FPType v)
  104. {
  105. FPInterval w;
  106. auto saveMode = std::fegetround();
  107. std::fesetround(FE_DOWNWARD);
  108. w.mEndpoints[0] = u * v;
  109. std::fesetround(FE_UPWARD);
  110. w.mEndpoints[1] = u * v;
  111. std::fesetround(saveMode);
  112. return w;
  113. }
  114. inline static FPInterval Div(FPType u, FPType v)
  115. {
  116. FPType const zero = static_cast<FPType>(0);
  117. if (v != zero)
  118. {
  119. FPInterval w;
  120. auto saveMode = std::fegetround();
  121. std::fesetround(FE_DOWNWARD);
  122. w.mEndpoints[0] = u / v;
  123. std::fesetround(FE_UPWARD);
  124. w.mEndpoints[1] = u / v;
  125. std::fesetround(saveMode);
  126. return w;
  127. }
  128. else
  129. {
  130. // Division by zero does not lead to a determinate FPInterval.
  131. // Just return the entire set of real numbers.
  132. return Reals();
  133. }
  134. }
  135. private:
  136. std::array<FPType, 2> mEndpoints;
  137. public:
  138. // FOR INTERNAL USE ONLY. These are used by the non-class operators
  139. // defined after the class definition.
  140. inline static FPInterval Add(FPType u0, FPType u1, FPType v0, FPType v1)
  141. {
  142. FPInterval w;
  143. auto saveMode = std::fegetround();
  144. std::fesetround(FE_DOWNWARD);
  145. w.mEndpoints[0] = u0 + v0;
  146. std::fesetround(FE_UPWARD);
  147. w.mEndpoints[1] = u1 + v1;
  148. std::fesetround(saveMode);
  149. return w;
  150. }
  151. inline static FPInterval Sub(FPType u0, FPType u1, FPType v0, FPType v1)
  152. {
  153. FPInterval w;
  154. auto saveMode = std::fegetround();
  155. std::fesetround(FE_DOWNWARD);
  156. w.mEndpoints[0] = u0 - v1;
  157. std::fesetround(FE_UPWARD);
  158. w.mEndpoints[1] = u1 - v0;
  159. std::fesetround(saveMode);
  160. return w;
  161. }
  162. inline static FPInterval Mul(FPType u0, FPType u1, FPType v0, FPType v1)
  163. {
  164. FPInterval w;
  165. auto saveMode = std::fegetround();
  166. std::fesetround(FE_DOWNWARD);
  167. w.mEndpoints[0] = u0 * v0;
  168. std::fesetround(FE_UPWARD);
  169. w.mEndpoints[1] = u1 * v1;
  170. std::fesetround(saveMode);
  171. return w;
  172. }
  173. inline static FPInterval Mul2(FPType u0, FPType u1, FPType v0, FPType v1)
  174. {
  175. auto saveMode = std::fegetround();
  176. std::fesetround(FE_DOWNWARD);
  177. FPType u0mv1 = u0 * v1;
  178. FPType u1mv0 = u1 * v0;
  179. std::fesetround(FE_UPWARD);
  180. FPType u0mv0 = u0 * v0;
  181. FPType u1mv1 = u1 * v1;
  182. std::fesetround(saveMode);
  183. return FPInterval<FPType>(std::min(u0mv1, u1mv0), std::max(u0mv0, u1mv1));
  184. }
  185. inline static FPInterval Div(FPType u0, FPType u1, FPType v0, FPType v1)
  186. {
  187. FPInterval w;
  188. auto saveMode = std::fegetround();
  189. std::fesetround(FE_DOWNWARD);
  190. w.mEndpoints[0] = u0 / v1;
  191. std::fesetround(FE_UPWARD);
  192. w.mEndpoints[1] = u1 / v0;
  193. std::fesetround(saveMode);
  194. return w;
  195. }
  196. inline static FPInterval Reciprocal(FPType v0, FPType v1)
  197. {
  198. FPType const one = static_cast<FPType>(1);
  199. FPInterval w;
  200. auto saveMode = std::fegetround();
  201. std::fesetround(FE_DOWNWARD);
  202. w.mEndpoints[0] = one / v1;
  203. std::fesetround(FE_UPWARD);
  204. w.mEndpoints[1] = one / v0;
  205. std::fesetround(saveMode);
  206. return w;
  207. }
  208. inline static FPInterval ReciprocalDown(FPType v)
  209. {
  210. auto saveMode = std::fegetround();
  211. std::fesetround(FE_DOWNWARD);
  212. FPType recpv = static_cast<FPType>(1) / v;
  213. std::fesetround(saveMode);
  214. FPType const inf = std::numeric_limits<FPType>::infinity();
  215. return FPInterval<FPType>(recpv, +inf);
  216. }
  217. inline static FPInterval ReciprocalUp(FPType v)
  218. {
  219. auto saveMode = std::fegetround();
  220. std::fesetround(FE_UPWARD);
  221. FPType recpv = static_cast<FPType>(1) / v;
  222. std::fesetround(saveMode);
  223. FPType const inf = std::numeric_limits<FPType>::infinity();
  224. return FPInterval<FPType>(-inf, recpv);
  225. }
  226. inline static FPInterval Reals()
  227. {
  228. FPType const inf = std::numeric_limits<FPType>::infinity();
  229. return FPInterval(-inf, +inf);
  230. }
  231. };
  232. // Unary operations. Negation of [e0,e1] produces [-e1,-e0]. This
  233. // operation needs to be supported in the sense of negating a
  234. // "number" in an arithmetic expression.
  235. template <typename FPType>
  236. FPInterval<FPType> operator+(FPInterval<FPType> const& u)
  237. {
  238. return u;
  239. }
  240. template <typename FPType>
  241. FPInterval<FPType> operator-(FPInterval<FPType> const& u)
  242. {
  243. return FPInterval<FPType>(-u[1], -u[0]);
  244. }
  245. // Addition operations.
  246. template <typename FPType>
  247. FPInterval<FPType> operator+(FPType u, FPInterval<FPType> const& v)
  248. {
  249. return FPInterval<FPType>::Add(u, u, v[0], v[1]);
  250. }
  251. template <typename FPType>
  252. FPInterval<FPType> operator+(FPInterval<FPType> const& u, FPType v)
  253. {
  254. return FPInterval<FPType>::Add(u[0], u[1], v, v);
  255. }
  256. template <typename FPType>
  257. FPInterval<FPType> operator+(FPInterval<FPType> const& u, FPInterval<FPType> const& v)
  258. {
  259. return FPInterval<FPType>::Add(u[0], u[1], v[0], v[1]);
  260. }
  261. // Subtraction operations.
  262. template <typename FPType>
  263. FPInterval<FPType> operator-(FPType u, FPInterval<FPType> const& v)
  264. {
  265. return FPInterval<FPType>::Sub(u, u, v[0], v[1]);
  266. }
  267. template <typename FPType>
  268. FPInterval<FPType> operator-(FPInterval<FPType> const& u, FPType v)
  269. {
  270. return FPInterval<FPType>::Sub(u[0], u[1], v, v);
  271. }
  272. template <typename FPType>
  273. FPInterval<FPType> operator-(FPInterval<FPType> const& u, FPInterval<FPType> const& v)
  274. {
  275. return FPInterval<FPType>::Sub(u[0], u[1], v[0], v[1]);
  276. }
  277. // Multiplication operations.
  278. template <typename FPType>
  279. FPInterval<FPType> operator*(FPType u, FPInterval<FPType> const& v)
  280. {
  281. FPType const zero = static_cast<FPType>(0);
  282. if (u >= zero)
  283. {
  284. return FPInterval<FPType>::Mul(u, u, v[0], v[1]);
  285. }
  286. else
  287. {
  288. return FPInterval<FPType>::Mul(u, u, v[1], v[0]);
  289. }
  290. }
  291. template <typename FPType>
  292. FPInterval<FPType> operator*(FPInterval<FPType> const& u, FPType v)
  293. {
  294. FPType const zero = static_cast<FPType>(0);
  295. if (v >= zero)
  296. {
  297. return FPInterval<FPType>::Mul(u[0], u[1], v, v);
  298. }
  299. else
  300. {
  301. return FPInterval<FPType>::Mul(u[1], u[0], v, v);
  302. }
  303. }
  304. template <typename FPType>
  305. FPInterval<FPType> operator*(FPInterval<FPType> const& u, FPInterval<FPType> const& v)
  306. {
  307. FPType const zero = static_cast<FPType>(0);
  308. if (u[0] >= zero)
  309. {
  310. if (v[0] >= zero)
  311. {
  312. return FPInterval<FPType>::Mul(u[0], u[1], v[0], v[1]);
  313. }
  314. else if (v[1] <= zero)
  315. {
  316. return FPInterval<FPType>::Mul(u[1], u[0], v[0], v[1]);
  317. }
  318. else // v[0] < 0 < v[1]
  319. {
  320. return FPInterval<FPType>::Mul(u[1], u[1], v[0], v[1]);
  321. }
  322. }
  323. else if (u[1] <= zero)
  324. {
  325. if (v[0] >= zero)
  326. {
  327. return FPInterval<FPType>::Mul(u[0], u[1], v[1], v[0]);
  328. }
  329. else if (v[1] <= zero)
  330. {
  331. return FPInterval<FPType>::Mul(u[1], u[0], v[1], v[0]);
  332. }
  333. else // v[0] < 0 < v[1]
  334. {
  335. return FPInterval<FPType>::Mul(u[0], u[0], v[1], v[0]);
  336. }
  337. }
  338. else // u[0] < 0 < u[1]
  339. {
  340. if (v[0] >= zero)
  341. {
  342. return FPInterval<FPType>::Mul(u[0], u[1], v[1], v[1]);
  343. }
  344. else if (v[1] <= zero)
  345. {
  346. return FPInterval<FPType>::Mul(u[1], u[0], v[0], v[0]);
  347. }
  348. else // v[0] < 0 < v[1]
  349. {
  350. return FPInterval<FPType>::Mul2(u[0], u[1], v[0], v[1]);
  351. }
  352. }
  353. }
  354. // Division operations. If the divisor FPInterval is [v0,v1] with
  355. // v0 < 0 < v1, then the returned FPInterval is (-infinity,+infinity)
  356. // instead of Union((-infinity,1/v0),(1/v1,+infinity)). An application
  357. // should try to avoid this case by branching based on [v0,0] and [0,v1].
  358. template <typename FPType>
  359. FPInterval<FPType> operator/(FPType u, FPInterval<FPType> const& v)
  360. {
  361. FPType const zero = static_cast<FPType>(0);
  362. if (v[0] > zero || v[1] < zero)
  363. {
  364. return u * FPInterval<FPType>::Reciprocal(v[0], v[1]);
  365. }
  366. else
  367. {
  368. if (v[0] == zero)
  369. {
  370. return u * FPInterval<FPType>::ReciprocalDown(v[1]);
  371. }
  372. else if (v[1] == zero)
  373. {
  374. return u * FPInterval<FPType>::ReciprocalUp(v[0]);
  375. }
  376. else // v[0] < 0 < v[1]
  377. {
  378. return FPInterval<FPType>::Reals();
  379. }
  380. }
  381. }
  382. template <typename FPType>
  383. FPInterval<FPType> operator/(FPInterval<FPType> const& u, FPType v)
  384. {
  385. FPType const zero = static_cast<FPType>(0);
  386. if (v > zero)
  387. {
  388. return FPInterval<FPType>::Div(u[0], u[1], v, v);
  389. }
  390. else if (v < zero)
  391. {
  392. return FPInterval<FPType>::Div(u[1], u[0], v, v);
  393. }
  394. else // v = 0
  395. {
  396. return FPInterval<FPType>::Reals();
  397. }
  398. }
  399. template <typename FPType>
  400. FPInterval<FPType> operator/(FPInterval<FPType> const& u, FPInterval<FPType> const& v)
  401. {
  402. FPType const zero = static_cast<FPType>(0);
  403. if (v[0] > zero || v[1] < zero)
  404. {
  405. return u * FPInterval<FPType>::Reciprocal(v[0], v[1]);
  406. }
  407. else
  408. {
  409. if (v[0] == zero)
  410. {
  411. return u * FPInterval<FPType>::ReciprocalDown(v[1]);
  412. }
  413. else if (v[1] == zero)
  414. {
  415. return u * FPInterval<FPType>::ReciprocalUp(v[0]);
  416. }
  417. else // v[0] < 0 < v[1]
  418. {
  419. return FPInterval<FPType>::Reals();
  420. }
  421. }
  422. }
  423. }