#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2021 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #ifndef NUCLEX_PIXELS_HALF_H #define NUCLEX_PIXELS_HALF_H #include "Nuclex/Pixels/Config.h" #include // for std::uint16_t #include // for std::numeric_limits namespace Nuclex { namespace Pixels { // ------------------------------------------------------------------------------------------- // /// Half-precision (16 bit) floating point number /// /// The format matches the IEEE-754 binary-16 specification /// http://en.wikipedia.org/wiki/Half-precision_floating-point_format /// class NUCLEX_PIXELS_TYPE Half { /// The value 1.0 as a half-precision float public: NUCLEX_PIXELS_API static const Half One; /// The value 0.0 as a half-precision float public: NUCLEX_PIXELS_API static const Half Zero; /// Initializes a new half-precision floating point value /// /// To emulate the behavior of other C++ primitive types, the value remains /// uninitialized and it is up to the user to make sure a value is assigned before /// the variable is accessed. /// public: NUCLEX_PIXELS_API Half() {} /* /// Initializes a half-precision floating point value as copy of another public: NUCLEX_PIXELS_API Half(const Half &other) : bits(other.bits) {} */ /// Initializes a new half-precision floating point value /// Floating point value the half will be initialized with public: NUCLEX_PIXELS_API Half(float value) : bits(BitsFromFloat(value)) {} /// Converts the half precision floating point value into a float /// A float equivalent to the half precision floating point value public: NUCLEX_PIXELS_API operator float() const { return FloatFromBits(this->bits); } /// Builds a half directly from bits stored in a 16 bit unsigned integer /// Bits of the half precision integer /// The half precision integer constructed from the provided bits public: NUCLEX_PIXELS_API static Half FromBits(std::uint16_t bits) { Half value; value.bits = bits; return value; } /// Returns the bits of the half stored in a 16 bit unsigned integer /// A 16 unsigned integer containing the bits making up the half public: NUCLEX_PIXELS_API std::uint16_t GetBits() const { return this->bits; } // CHECK: Find method to convert a normalized byte to half without converting to float /// Converts a byte into a half precision float /// Byte that will be converted /// The half-precision float equivalent to the byte public: NUCLEX_PIXELS_API static Half FromNormalizedByte(std::uint8_t value) { float valueAsFloat = static_cast(value) / 255.0f; return Half(valueAsFloat); } // CHECK: Find method to convert a half to normalized byte without converting to float /// Converts the half precision float into a normalized byte /// The equivalent normalized byte to the input half-precision float public: NUCLEX_PIXELS_API std::uint8_t ToNormalizedByte() const { float valueAsFloat = FloatFromBits(this->bits); if(valueAsFloat <= 0.0f) { return 0; } else if(valueAsFloat >= 1.0f) { return 255; } else { return static_cast(valueAsFloat * 255.0f + 0.5f); } } /// /// Converts a floating point value into a half-precision floating point value /// /// Floating point value that will be converted /// /// The equivalent half-precision floating point value to the input value /// /// /// Based on a code snippet by Phermost /// http://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion /// public: NUCLEX_PIXELS_API static std::uint16_t BitsFromFloat(float value); /// /// Converts a half-precision floating point value to a floating point value /// /// Half-precision floating point bits that will be converted /// The equivalent floating point value to the input value /// /// Based on a code snippet by Phermost /// http://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion /// public: NUCLEX_PIXELS_API static float FloatFromBits(std::uint16_t bits); /// Stores the bits of the half-precision floating point value private: std::uint16_t bits; }; // ------------------------------------------------------------------------------------------- // }} // namespace Nuclex::Pixels namespace std { // ------------------------------------------------------------------------------------------- // /// Numeric limits for half precision floats /// /// Users are not allowed to add anything to the std namespace. However, an exception /// has been defined for supporting custom, non-complex types in std::numeric_limits. /// template<> class numeric_limits { /// Type for which the class is providing informations public: typedef Nuclex::Pixels::Half _Ty; /// /// Minimum finite positive value that is representable by a half precision float /// public: static _Ty min() throw() { return _Ty(std::uint16_t(1024)); } /// /// Maximum finite value that is representable by a half precision float /// public: static _Ty max() throw() { return _Ty(std::uint16_t(31743)); } /// /// Lowest finite value that is representable by a half precision float /// public: static _Ty lowest() throw() { return _Ty(std::uint16_t(64511)); } /// Smallest effective increment from the value 1.0 public: static _Ty epsilon() throw() { return _Ty(std::uint16_t(0x3c01)); } /// Largest possible rounding error within representable numeric range public: static _Ty round_error() throw() { return _Ty::Zero; // TODO: Determine rounding error } /// Minimum denormalized value public: static _Ty denorm_min() throw() { return _Ty::Zero; // TODO: Determine minimum denormalized value } /// Positive infinity public: static _Ty infinity() throw() { return _Ty(std::uint16_t(0x7c00)); } /// A quiet not-a-number value public: static _Ty quiet_NaN() throw() { return _Ty::Zero; // TODO: Determine quiet not-a-number value } /// A signaling not-a-number value public: static _Ty signaling_NaN() throw() { return _Ty::Zero; // TODO: Determine signaling not-a-number value } /// Number of binary digits that can directly be represented (mantissa) public: const int digits = 0; // TODO: Determine mantissa /// Number of base10 digits that can directly be represented public: const int digits10 = 0; // TODO: Determine base10 directly representable digits /// I have no idea... public: const int max_digits10 = 0; // TODO: Determine whatever this is /// I have no idea... public: const int max_exponent = 0; // TODO: Determine whatever this is /// I have no idea... public: const int max_exponent10 = 0; // TODO: Determine whatever this is /// I have no idea... public: const int min_exponent = 0; // TODO: Determine whatever this is /// I have no idea... public: const int min_exponent10 = 0; // TODO: Determine whatever this is private: numeric_limits(const numeric_limits &); private: numeric_limits &operator =(const numeric_limits &); }; // ------------------------------------------------------------------------------------------- // } #endif // NUCLEX_PIXELS_HALF_H