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

////////////////////////////////////////////////////////////////////
// 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__