// Copyright (C) 2013 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_FLOAT_DEtAILS_Hh_ #define DLIB_FLOAT_DEtAILS_Hh_ #include #include "algs.h" #include namespace dlib { struct float_details { /*! WHAT THIS OBJECT REPRESENTS This object is a tool for converting floating point numbers into an explicit integer representation and then also converting back. In particular, a float_details object represents a floating point number with a 64 bit mantissa and 16 bit exponent. These are stored in the public fields of the same names. The main use of this object is to convert floating point values into a known uniform representation so they can be serialized to an output stream. This allows dlib serialization code to work on any system, regardless of the floating point representation used by the hardware. It also means that, for example, a double can be serialized and then deserialized into a float and it will perform the appropriate conversion. In more detail, this object represents a floating point value equal to mantissa*pow(2,exponent), except when exponent takes on any of the following special values: - is_inf - is_ninf - is_nan These values are used to indicate that the floating point value should be either infinity, negative infinity, or not-a-number respectively. !*/ float_details( int64 man, int16 exp ) : mantissa(man), exponent(exp) {} /*! ensures - #mantissa == man - #exponent == exp !*/ float_details() : mantissa(0), exponent(0) {} /*! ensures - this object represents a floating point value of 0 !*/ float_details ( const double& val) { *this = val; } float_details ( const float& val) { *this = val; } float_details ( const long double& val) { *this = val; } /*! ensures - converts the given value into a float_details representation. This means that converting #*this back into a floating point number should recover the input val. !*/ float_details& operator= ( const double& val) { convert_from_T(val); return *this; } float_details& operator= ( const float& val) { convert_from_T(val); return *this; } float_details& operator= ( const long double& val) { convert_from_T(val); return *this; } /*! ensures - converts the given value into a float_details representation. This means that converting #*this back into a floating point number should recover the input val. !*/ operator double () const { return convert_to_T(); } operator float () const { return convert_to_T(); } operator long double () const { return convert_to_T(); } /*! ensures - converts the contents of this float_details object into a floating point number. !*/ const static int16 is_inf = 32000; const static int16 is_ninf = 32001; const static int16 is_nan = 32002; int64 mantissa; int16 exponent; private: // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // IMPLEMENTATION DETAILS // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template void convert_from_T ( const T& val ) { mantissa = 0; const int digits = dlib::tmin::digits, 63>::value; if (val == std::numeric_limits::infinity()) { exponent = is_inf; } else if (val == -std::numeric_limits::infinity()) { exponent = is_ninf; } else if (val < std::numeric_limits::infinity()) { int exp; mantissa = static_cast(std::frexp(val, &exp)*(((uint64)1)<>= 8; exponent += 8; } } else { exponent = is_nan; } } template T convert_to_T ( ) const { if (exponent < is_inf) return std::ldexp((T)mantissa, exponent); else if (exponent == is_inf) return std::numeric_limits::infinity(); else if (exponent == is_ninf) return -std::numeric_limits::infinity(); else return std::numeric_limits::quiet_NaN(); } }; } #endif // DLIB_FLOAT_DEtAILS_Hh_