//////////////////////////////////////////////////////////////////// // HalfFoat.h // // Copyright 2007 cDc@seacave // Distributed under the Boost Software License, Version 1.0 // (See http://www.boost.org/LICENSE_1_0.txt) #ifndef __SEACAVE_HALFFLOAT_H__ #define __SEACAVE_HALFFLOAT_H__ // I N C L U D E S ///////////////////////////////////////////////// // D E F I N E S /////////////////////////////////////////////////// namespace SEACAVE { // S T R U C T S /////////////////////////////////////////////////// // hfloat - a 16-bit floating point number class // // Can represent positive and negative numbers whose magnitude is between // roughly 6.1e-5 and 6.5e+4 with a relative error of 9.8e-4; numbers // smaller than 6.1e-5 can be represented with an absolute error of // 6.0e-8. All integers from -2048 to +2048 can be represented exactly. // Supports Denormals-as-zero (DAZ), but does not support infinities or NaN. // // Only conversions from half to float are lossless. class GENERAL_API hfloat { public: typedef short Type; inline hfloat() : val(fromFloat(float())) {} explicit inline hfloat(float v) : val(fromFloat(v)) {} template inline hfloat(T v) : val(fromFloat(static_cast(v))) {} inline hfloat& operator = (float v) { val = fromFloat(v); return *this; } template inline hfloat& operator = (T v) { val = fromFloat(static_cast(v)); return *this; } inline operator float() const { return toFloat(val); } inline hfloat operator - () const { return fromFloat2HFloat(-toFloat(val)); } inline hfloat operator + (hfloat v) { return fromFloat2HFloat(toFloat(val) + toFloat(v.val)); } inline hfloat operator + (float v) { return fromFloat2HFloat(toFloat(val) + v); } inline hfloat& operator += (hfloat v) { return *this = *this + v; } inline hfloat& operator += (float v) { return *this = *this + v; } inline hfloat operator - (hfloat v) { return fromFloat2HFloat(toFloat(val) - toFloat(v.val)); } inline hfloat operator - (float v) { return fromFloat2HFloat(toFloat(val) - v); } inline hfloat& operator -= (hfloat v) { return *this = *this - v; } inline hfloat& operator -= (float v) { return *this = *this - v; } inline hfloat operator * (hfloat v) { return fromFloat2HFloat(toFloat(val) * toFloat(v.val)); } inline hfloat operator * (float v) { return fromFloat2HFloat(toFloat(val) * v); } inline hfloat& operator *= (hfloat v) { return *this = *this * v; } inline hfloat& operator *= (float v) { return *this = *this * v; } inline hfloat operator / (hfloat v) { return fromFloat2HFloat(toFloat(val) / toFloat(v.val)); } inline hfloat operator / (float v) { return fromFloat2HFloat(toFloat(val) / v); } inline hfloat& operator /= (hfloat v) { return *this = *this / v; } inline hfloat& operator /= (float v) { return *this = *this / v; } static float min() { return 6.1e-5f; } static float max() { return 6.5e+4f; } static inline short fromFloat(float f) { ASSERT(ISFINITE(f) && (ABS(f) == 0.f || ABS(f) >= min()) && ABS(f) <= max()); // ~8 clock cycles on modern x86-64 const CastF2I ufi(f); int32_t t1 = ufi.i & 0x7fffffff; // Non-sign bits int32_t t2 = ufi.i & 0x80000000; // Sign bit int32_t t3 = ufi.i & 0x7f800000; // Exponent t1 >>= 13; // Align mantissa on MSB t2 >>= 16; // Shift sign bit into position t1 -= 0x1c000; // Adjust bias t1 = (t3 < 0x38800000) ? 0 : t1; // Flush-to-zero t1 = (t3 > 0x47000000) ? 0x7bff : t1; // Clamp-to-max t1 = (t3 == 0 ? 0 : t1); // Denormals-as-zero return (short)(t1 | t2); // Re-insert sign bit } static inline float toFloat(short h) { // ~6 clock cycles on modern x86-64 CastF2I ufi; int32_t t1 = h & 0x7fff; // Non-sign bits int32_t t2 = h & 0x8000; // Sign bit int32_t t3 = h & 0x7c00; // Exponent t1 <<= 13; // Align mantissa on MSB t2 <<= 16; // Shift sign bit into position t1 += 0x38000000; // Adjust bias t1 = (t3 == 0 ? 0 : t1); // Denormals-as-zero ufi.i = t1 | t2; // Re-insert sign bit return ufi.f; } #ifdef _USE_BOOST // serialize template void serialize(Archive& ar, const unsigned int /*version*/) { ar & val; } #endif protected: static inline hfloat fromFloat2HFloat(float f) { return TAliasCast(fromFloat(f)).i; } protected: Type val; }; /*----------------------------------------------------------------*/ } // namespace SEACAVE #endif // __SEACAVE_HALFFLOAT_H__