You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
4.5 KiB
159 lines
4.5 KiB
//////////////////////////////////////////////////////////////////// |
|
// 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 <typename T> |
|
inline hfloat(T v) : val(fromFloat(static_cast<float>(v))) {} |
|
|
|
inline hfloat& operator = (float v) { |
|
val = fromFloat(v); |
|
return *this; |
|
} |
|
template <typename T> |
|
inline hfloat& operator = (T v) { |
|
val = fromFloat(static_cast<float>(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 <class Archive> |
|
void serialize(Archive& ar, const unsigned int /*version*/) { |
|
ar & val; |
|
} |
|
#endif |
|
|
|
protected: |
|
static inline hfloat fromFloat2HFloat(float f) { |
|
return TAliasCast<short,hfloat>(fromFloat(f)).i; |
|
} |
|
|
|
protected: |
|
Type val; |
|
}; |
|
/*----------------------------------------------------------------*/ |
|
|
|
} // namespace SEACAVE |
|
|
|
#endif // __SEACAVE_HALFFLOAT_H__
|
|
|