123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.09.14
- #pragma once
- #include <cstdint>
- namespace WwiseGTE
- {
- template <typename Float, typename UInt, int NumBits, int Precision>
- class IEEEBinary
- {
- public:
- // For generic access of the template types.
- using FloatType = Float;
- using UIntType = UInt;
- // Construction from an encoding. Copy constructor, destructor, and
- // assignment operator are implicitly generated. For the 3-parameter
- // constructor, see the comments for SetEncoding(...).
- ~IEEEBinary() = default;
- IEEEBinary() = default;
- IEEEBinary(IEEEBinary const& object)
- :
- encoding(object.encoding)
- {
- }
- IEEEBinary(UInt inEncoding)
- :
- encoding(inEncoding)
- {
- }
- IEEEBinary(UInt inSign, UInt inBiased, UInt inTrailing)
- {
- SetEncoding(inSign, inBiased, inTrailing);
- }
- IEEEBinary(Float inNumber)
- :
- number(inNumber)
- {
- }
- // Implicit conversion to floating-point type.
- inline operator UInt () const
- {
- return encoding;
- }
- inline operator Float () const
- {
- return number;
- }
- // Assignment.
- IEEEBinary& operator= (IEEEBinary const& object)
- {
- encoding = object.encoding;
- return *this;
- }
- // Special constants.
- static int const NUM_ENCODING_BITS = NumBits;
- static int const NUM_EXPONENT_BITS = NumBits - Precision;
- static int const NUM_SIGNIFICAND_BITS = Precision;
- static int const NUM_TRAILING_BITS = Precision - 1;
- static int const EXPONENT_BIAS = (1 << (NUM_EXPONENT_BITS - 1)) - 1;
- static int const MAX_BIASED_EXPONENT = (1 << NUM_EXPONENT_BITS) - 1;
- static int const MIN_SUB_EXPONENT = 1 - EXPONENT_BIAS;
- static int const MIN_EXPONENT = MIN_SUB_EXPONENT - NUM_TRAILING_BITS;
- static int const SIGN_SHIFT = NumBits - 1;
- static UInt const SIGN_MASK = (UInt(1) << (NumBits - 1));
- static UInt const NOT_SIGN_MASK = UInt(~SIGN_MASK);
- static UInt const TRAILING_MASK = (UInt(1) << NUM_TRAILING_BITS) - 1;
- static UInt const EXPONENT_MASK = NOT_SIGN_MASK & ~TRAILING_MASK;
- static UInt const NAN_QUIET_MASK = (UInt(1) << (NUM_TRAILING_BITS - 1));
- static UInt const NAN_PAYLOAD_MASK = (TRAILING_MASK >> 1);
- static UInt const MAX_TRAILING = TRAILING_MASK;
- static UInt const SUP_TRAILING = (UInt(1) << NUM_TRAILING_BITS);
- static UInt const POS_ZERO = UInt(0);
- static UInt const NEG_ZERO = SIGN_MASK;
- static UInt const MIN_SUBNORMAL = UInt(1);
- static UInt const MAX_SUBNORMAL = TRAILING_MASK;
- static UInt const MIN_NORMAL = SUP_TRAILING;
- static UInt const MAX_NORMAL = NOT_SIGN_MASK & ~SUP_TRAILING;
- static UInt const POS_INFINITY = EXPONENT_MASK;
- static UInt const NEG_INFINITY = SIGN_MASK | EXPONENT_MASK;
- // The types of numbers.
- enum Classification
- {
- CLASS_NEG_INFINITY,
- CLASS_NEG_SUBNORMAL,
- CLASS_NEG_NORMAL,
- CLASS_NEG_ZERO,
- CLASS_POS_ZERO,
- CLASS_POS_SUBNORMAL,
- CLASS_POS_NORMAL,
- CLASS_POS_INFINITY,
- CLASS_QUIET_NAN,
- CLASS_SIGNALING_NAN
- };
- Classification GetClassification() const
- {
- UInt sign, biased, trailing;
- GetEncoding(sign, biased, trailing);
- if (biased == 0)
- {
- if (trailing == 0)
- {
- return (sign != 0 ? CLASS_NEG_ZERO : CLASS_POS_ZERO);
- }
- else
- {
- return (sign != 0 ? CLASS_NEG_SUBNORMAL : CLASS_POS_SUBNORMAL);
- }
- }
- else if (biased < MAX_BIASED_EXPONENT)
- {
- return (sign != 0 ? CLASS_NEG_NORMAL : CLASS_POS_NORMAL);
- }
- else if (trailing == 0)
- {
- return (sign != 0 ? CLASS_NEG_INFINITY : CLASS_POS_INFINITY);
- }
- else if (trailing & NAN_QUIET_MASK)
- {
- return CLASS_QUIET_NAN;
- }
- else
- {
- return CLASS_SIGNALING_NAN;
- }
- }
- bool IsZero() const
- {
- return encoding == POS_ZERO || encoding == NEG_ZERO;
- }
- bool IsSignMinus() const
- {
- return (encoding & SIGN_MASK) != 0;
- }
- bool IsSubnormal() const
- {
- return GetBiased() == 0 && GetTrailing() > 0;
- }
- bool IsNormal() const
- {
- UInt biased = GetBiased();
- return 0 < biased&& biased < MAX_BIASED_EXPONENT;
- }
- bool IsFinite() const
- {
- return GetBiased() < MAX_BIASED_EXPONENT;
- }
- bool IsInfinite() const
- {
- return GetBiased() == MAX_BIASED_EXPONENT && GetTrailing() == 0;
- }
- bool IsNaN() const
- {
- return GetBiased() == MAX_BIASED_EXPONENT && GetTrailing() != 0;
- }
- bool IsSignalingNaN() const
- {
- UInt trailing = GetTrailing();
- return GetBiased() == MAX_BIASED_EXPONENT
- && (trailing & NAN_QUIET_MASK) == 0
- && (trailing & NAN_PAYLOAD_MASK) != 0;
- }
- // Get neighboring numbers.
- UInt GetNextUp() const
- {
- UInt sign, biased, trailing;
- GetEncoding(sign, biased, trailing);
- if (biased == 0)
- {
- if (trailing == 0)
- {
- // The next-up for both -0 and +0 is MIN_SUBNORMAL.
- return MIN_SUBNORMAL;
- }
- else
- {
- if (sign != 0)
- {
- // When trailing is 1, 'this' is -MIN_SUBNORMAL and next-up
- // is -0.
- --trailing;
- return SIGN_MASK | trailing;
- }
- else
- {
- // When trailing is MAX_TRAILING, 'this' is MAX_SUBNORMAL
- // and next-up is MIN_NORMAL.
- ++trailing;
- return trailing;
- }
- }
- }
- else if (biased < MAX_BIASED_EXPONENT)
- {
- UInt nonnegative = (encoding & NOT_SIGN_MASK);
- if (sign != 0)
- {
- --nonnegative;
- return SIGN_MASK | nonnegative;
- }
- else
- {
- ++nonnegative;
- return nonnegative;
- }
- }
- else if (trailing == 0)
- {
- if (sign != 0)
- {
- // The next-up of -INFINITY is -MAX_NORMAL.
- return SIGN_MASK | MAX_NORMAL;
- }
- else
- {
- // The next-up of +INFINITY is +INFINITY.
- return POS_INFINITY;
- }
- }
- else if (trailing & NAN_QUIET_MASK)
- {
- // TODO. The IEEE standard is not clear what to do here. Figure
- // out what it means.
- return 0;
- }
- else
- {
- // TODO. The IEEE standard is not clear what to do here. Figure
- // out what it means.
- return 0;
- }
- }
- UInt GetNextDown() const
- {
- UInt sign, biased, trailing;
- GetEncoding(sign, biased, trailing);
- if (biased == 0)
- {
- if (trailing == 0)
- {
- // The next-down for both -0 and +0 is -MIN_SUBNORMAL.
- return SIGN_MASK | MIN_SUBNORMAL;
- }
- else
- {
- if (sign == 0)
- {
- // When trailing is 1, 'this' is MIN_SUBNORMAL and next-down
- // is +0.
- --trailing;
- return trailing;
- }
- else
- {
- // When trailing is MAX_TRAILING, 'this' is -MAX_SUBNORMAL
- // and next-down is -MIN_NORMAL.
- ++trailing;
- return SIGN_MASK | trailing;
- }
- }
- }
- else if (biased < MAX_BIASED_EXPONENT)
- {
- UInt nonnegative = (encoding & NOT_SIGN_MASK);
- if (sign == 0)
- {
- --nonnegative;
- return nonnegative;
- }
- else
- {
- ++nonnegative;
- return SIGN_MASK | nonnegative;
- }
- }
- else if (trailing == 0)
- {
- if (sign == 0)
- {
- // The next-down of +INFINITY is +MAX_NORMAL.
- return MAX_NORMAL;
- }
- else
- {
- // The next-down of -INFINITY is -INFINITY.
- return NEG_INFINITY;
- }
- }
- else if (trailing & NAN_QUIET_MASK)
- {
- // TODO. The IEEE standard is not clear what to do here. Figure
- // out what it means.
- return 0;
- }
- else
- {
- // TODO. The IEEE standard is not clear what to do here. Figure
- // out what it means.
- return 0;
- }
- }
- // Encode and decode the binary representation. The sign is 0 (number
- // is nonnegative) or 1 (number is negative). The biased exponent is
- // in the range [0,MAX_BIASED_EXPONENT]. The trailing significand is
- // in the range [0,MAX_TRAILING].
- UInt GetSign() const
- {
- return (encoding & SIGN_MASK) >> SIGN_SHIFT;
- }
- UInt GetBiased() const
- {
- return (encoding & EXPONENT_MASK) >> NUM_TRAILING_BITS;
- }
- UInt GetTrailing() const
- {
- return encoding & TRAILING_MASK;
- }
- void SetEncoding(UInt sign, UInt biased, UInt trailing)
- {
- encoding = (sign << SIGN_SHIFT) | (biased << NUM_TRAILING_BITS) | trailing;
- }
- void GetEncoding(UInt& sign, UInt& biased, UInt& trailing) const
- {
- sign = GetSign();
- biased = GetBiased();
- trailing = GetTrailing();
- }
- // Access for direct manipulation of the object.
- union
- {
- UInt encoding;
- Float number;
- };
- };
- using IEEEBinary32 = IEEEBinary<float, uint32_t, 32, 24>;
- using IEEEBinary64 = IEEEBinary<double, uint64_t, 64, 53>;
- }
|