IEEEBinary.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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.2019.09.14
  7. #pragma once
  8. #include <cstdint>
  9. namespace WwiseGTE
  10. {
  11. template <typename Float, typename UInt, int NumBits, int Precision>
  12. class IEEEBinary
  13. {
  14. public:
  15. // For generic access of the template types.
  16. using FloatType = Float;
  17. using UIntType = UInt;
  18. // Construction from an encoding. Copy constructor, destructor, and
  19. // assignment operator are implicitly generated. For the 3-parameter
  20. // constructor, see the comments for SetEncoding(...).
  21. ~IEEEBinary() = default;
  22. IEEEBinary() = default;
  23. IEEEBinary(IEEEBinary const& object)
  24. :
  25. encoding(object.encoding)
  26. {
  27. }
  28. IEEEBinary(UInt inEncoding)
  29. :
  30. encoding(inEncoding)
  31. {
  32. }
  33. IEEEBinary(UInt inSign, UInt inBiased, UInt inTrailing)
  34. {
  35. SetEncoding(inSign, inBiased, inTrailing);
  36. }
  37. IEEEBinary(Float inNumber)
  38. :
  39. number(inNumber)
  40. {
  41. }
  42. // Implicit conversion to floating-point type.
  43. inline operator UInt () const
  44. {
  45. return encoding;
  46. }
  47. inline operator Float () const
  48. {
  49. return number;
  50. }
  51. // Assignment.
  52. IEEEBinary& operator= (IEEEBinary const& object)
  53. {
  54. encoding = object.encoding;
  55. return *this;
  56. }
  57. // Special constants.
  58. static int const NUM_ENCODING_BITS = NumBits;
  59. static int const NUM_EXPONENT_BITS = NumBits - Precision;
  60. static int const NUM_SIGNIFICAND_BITS = Precision;
  61. static int const NUM_TRAILING_BITS = Precision - 1;
  62. static int const EXPONENT_BIAS = (1 << (NUM_EXPONENT_BITS - 1)) - 1;
  63. static int const MAX_BIASED_EXPONENT = (1 << NUM_EXPONENT_BITS) - 1;
  64. static int const MIN_SUB_EXPONENT = 1 - EXPONENT_BIAS;
  65. static int const MIN_EXPONENT = MIN_SUB_EXPONENT - NUM_TRAILING_BITS;
  66. static int const SIGN_SHIFT = NumBits - 1;
  67. static UInt const SIGN_MASK = (UInt(1) << (NumBits - 1));
  68. static UInt const NOT_SIGN_MASK = UInt(~SIGN_MASK);
  69. static UInt const TRAILING_MASK = (UInt(1) << NUM_TRAILING_BITS) - 1;
  70. static UInt const EXPONENT_MASK = NOT_SIGN_MASK & ~TRAILING_MASK;
  71. static UInt const NAN_QUIET_MASK = (UInt(1) << (NUM_TRAILING_BITS - 1));
  72. static UInt const NAN_PAYLOAD_MASK = (TRAILING_MASK >> 1);
  73. static UInt const MAX_TRAILING = TRAILING_MASK;
  74. static UInt const SUP_TRAILING = (UInt(1) << NUM_TRAILING_BITS);
  75. static UInt const POS_ZERO = UInt(0);
  76. static UInt const NEG_ZERO = SIGN_MASK;
  77. static UInt const MIN_SUBNORMAL = UInt(1);
  78. static UInt const MAX_SUBNORMAL = TRAILING_MASK;
  79. static UInt const MIN_NORMAL = SUP_TRAILING;
  80. static UInt const MAX_NORMAL = NOT_SIGN_MASK & ~SUP_TRAILING;
  81. static UInt const POS_INFINITY = EXPONENT_MASK;
  82. static UInt const NEG_INFINITY = SIGN_MASK | EXPONENT_MASK;
  83. // The types of numbers.
  84. enum Classification
  85. {
  86. CLASS_NEG_INFINITY,
  87. CLASS_NEG_SUBNORMAL,
  88. CLASS_NEG_NORMAL,
  89. CLASS_NEG_ZERO,
  90. CLASS_POS_ZERO,
  91. CLASS_POS_SUBNORMAL,
  92. CLASS_POS_NORMAL,
  93. CLASS_POS_INFINITY,
  94. CLASS_QUIET_NAN,
  95. CLASS_SIGNALING_NAN
  96. };
  97. Classification GetClassification() const
  98. {
  99. UInt sign, biased, trailing;
  100. GetEncoding(sign, biased, trailing);
  101. if (biased == 0)
  102. {
  103. if (trailing == 0)
  104. {
  105. return (sign != 0 ? CLASS_NEG_ZERO : CLASS_POS_ZERO);
  106. }
  107. else
  108. {
  109. return (sign != 0 ? CLASS_NEG_SUBNORMAL : CLASS_POS_SUBNORMAL);
  110. }
  111. }
  112. else if (biased < MAX_BIASED_EXPONENT)
  113. {
  114. return (sign != 0 ? CLASS_NEG_NORMAL : CLASS_POS_NORMAL);
  115. }
  116. else if (trailing == 0)
  117. {
  118. return (sign != 0 ? CLASS_NEG_INFINITY : CLASS_POS_INFINITY);
  119. }
  120. else if (trailing & NAN_QUIET_MASK)
  121. {
  122. return CLASS_QUIET_NAN;
  123. }
  124. else
  125. {
  126. return CLASS_SIGNALING_NAN;
  127. }
  128. }
  129. bool IsZero() const
  130. {
  131. return encoding == POS_ZERO || encoding == NEG_ZERO;
  132. }
  133. bool IsSignMinus() const
  134. {
  135. return (encoding & SIGN_MASK) != 0;
  136. }
  137. bool IsSubnormal() const
  138. {
  139. return GetBiased() == 0 && GetTrailing() > 0;
  140. }
  141. bool IsNormal() const
  142. {
  143. UInt biased = GetBiased();
  144. return 0 < biased&& biased < MAX_BIASED_EXPONENT;
  145. }
  146. bool IsFinite() const
  147. {
  148. return GetBiased() < MAX_BIASED_EXPONENT;
  149. }
  150. bool IsInfinite() const
  151. {
  152. return GetBiased() == MAX_BIASED_EXPONENT && GetTrailing() == 0;
  153. }
  154. bool IsNaN() const
  155. {
  156. return GetBiased() == MAX_BIASED_EXPONENT && GetTrailing() != 0;
  157. }
  158. bool IsSignalingNaN() const
  159. {
  160. UInt trailing = GetTrailing();
  161. return GetBiased() == MAX_BIASED_EXPONENT
  162. && (trailing & NAN_QUIET_MASK) == 0
  163. && (trailing & NAN_PAYLOAD_MASK) != 0;
  164. }
  165. // Get neighboring numbers.
  166. UInt GetNextUp() const
  167. {
  168. UInt sign, biased, trailing;
  169. GetEncoding(sign, biased, trailing);
  170. if (biased == 0)
  171. {
  172. if (trailing == 0)
  173. {
  174. // The next-up for both -0 and +0 is MIN_SUBNORMAL.
  175. return MIN_SUBNORMAL;
  176. }
  177. else
  178. {
  179. if (sign != 0)
  180. {
  181. // When trailing is 1, 'this' is -MIN_SUBNORMAL and next-up
  182. // is -0.
  183. --trailing;
  184. return SIGN_MASK | trailing;
  185. }
  186. else
  187. {
  188. // When trailing is MAX_TRAILING, 'this' is MAX_SUBNORMAL
  189. // and next-up is MIN_NORMAL.
  190. ++trailing;
  191. return trailing;
  192. }
  193. }
  194. }
  195. else if (biased < MAX_BIASED_EXPONENT)
  196. {
  197. UInt nonnegative = (encoding & NOT_SIGN_MASK);
  198. if (sign != 0)
  199. {
  200. --nonnegative;
  201. return SIGN_MASK | nonnegative;
  202. }
  203. else
  204. {
  205. ++nonnegative;
  206. return nonnegative;
  207. }
  208. }
  209. else if (trailing == 0)
  210. {
  211. if (sign != 0)
  212. {
  213. // The next-up of -INFINITY is -MAX_NORMAL.
  214. return SIGN_MASK | MAX_NORMAL;
  215. }
  216. else
  217. {
  218. // The next-up of +INFINITY is +INFINITY.
  219. return POS_INFINITY;
  220. }
  221. }
  222. else if (trailing & NAN_QUIET_MASK)
  223. {
  224. // TODO. The IEEE standard is not clear what to do here. Figure
  225. // out what it means.
  226. return 0;
  227. }
  228. else
  229. {
  230. // TODO. The IEEE standard is not clear what to do here. Figure
  231. // out what it means.
  232. return 0;
  233. }
  234. }
  235. UInt GetNextDown() const
  236. {
  237. UInt sign, biased, trailing;
  238. GetEncoding(sign, biased, trailing);
  239. if (biased == 0)
  240. {
  241. if (trailing == 0)
  242. {
  243. // The next-down for both -0 and +0 is -MIN_SUBNORMAL.
  244. return SIGN_MASK | MIN_SUBNORMAL;
  245. }
  246. else
  247. {
  248. if (sign == 0)
  249. {
  250. // When trailing is 1, 'this' is MIN_SUBNORMAL and next-down
  251. // is +0.
  252. --trailing;
  253. return trailing;
  254. }
  255. else
  256. {
  257. // When trailing is MAX_TRAILING, 'this' is -MAX_SUBNORMAL
  258. // and next-down is -MIN_NORMAL.
  259. ++trailing;
  260. return SIGN_MASK | trailing;
  261. }
  262. }
  263. }
  264. else if (biased < MAX_BIASED_EXPONENT)
  265. {
  266. UInt nonnegative = (encoding & NOT_SIGN_MASK);
  267. if (sign == 0)
  268. {
  269. --nonnegative;
  270. return nonnegative;
  271. }
  272. else
  273. {
  274. ++nonnegative;
  275. return SIGN_MASK | nonnegative;
  276. }
  277. }
  278. else if (trailing == 0)
  279. {
  280. if (sign == 0)
  281. {
  282. // The next-down of +INFINITY is +MAX_NORMAL.
  283. return MAX_NORMAL;
  284. }
  285. else
  286. {
  287. // The next-down of -INFINITY is -INFINITY.
  288. return NEG_INFINITY;
  289. }
  290. }
  291. else if (trailing & NAN_QUIET_MASK)
  292. {
  293. // TODO. The IEEE standard is not clear what to do here. Figure
  294. // out what it means.
  295. return 0;
  296. }
  297. else
  298. {
  299. // TODO. The IEEE standard is not clear what to do here. Figure
  300. // out what it means.
  301. return 0;
  302. }
  303. }
  304. // Encode and decode the binary representation. The sign is 0 (number
  305. // is nonnegative) or 1 (number is negative). The biased exponent is
  306. // in the range [0,MAX_BIASED_EXPONENT]. The trailing significand is
  307. // in the range [0,MAX_TRAILING].
  308. UInt GetSign() const
  309. {
  310. return (encoding & SIGN_MASK) >> SIGN_SHIFT;
  311. }
  312. UInt GetBiased() const
  313. {
  314. return (encoding & EXPONENT_MASK) >> NUM_TRAILING_BITS;
  315. }
  316. UInt GetTrailing() const
  317. {
  318. return encoding & TRAILING_MASK;
  319. }
  320. void SetEncoding(UInt sign, UInt biased, UInt trailing)
  321. {
  322. encoding = (sign << SIGN_SHIFT) | (biased << NUM_TRAILING_BITS) | trailing;
  323. }
  324. void GetEncoding(UInt& sign, UInt& biased, UInt& trailing) const
  325. {
  326. sign = GetSign();
  327. biased = GetBiased();
  328. trailing = GetTrailing();
  329. }
  330. // Access for direct manipulation of the object.
  331. union
  332. {
  333. UInt encoding;
  334. Float number;
  335. };
  336. };
  337. using IEEEBinary32 = IEEEBinary<float, uint32_t, 32, 24>;
  338. using IEEEBinary64 = IEEEBinary<double, uint64_t, 64, 53>;
  339. }