1 // Copyright (C) 2013 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_FLOAT_DEtAILS_Hh_ 4 #define DLIB_FLOAT_DEtAILS_Hh_ 5 6 #include <cmath> 7 #include "algs.h" 8 #include <limits> 9 10 namespace dlib 11 { 12 struct float_details 13 { 14 /*! 15 WHAT THIS OBJECT REPRESENTS 16 This object is a tool for converting floating point numbers into an 17 explicit integer representation and then also converting back. In 18 particular, a float_details object represents a floating point number with 19 a 64 bit mantissa and 16 bit exponent. These are stored in the public 20 fields of the same names. 21 22 The main use of this object is to convert floating point values into a 23 known uniform representation so they can be serialized to an output stream. 24 This allows dlib serialization code to work on any system, regardless of 25 the floating point representation used by the hardware. It also means 26 that, for example, a double can be serialized and then deserialized into a 27 float and it will perform the appropriate conversion. 28 29 30 In more detail, this object represents a floating point value equal to 31 mantissa*pow(2,exponent), except when exponent takes on any of the 32 following special values: 33 - is_inf 34 - is_ninf 35 - is_nan 36 These values are used to indicate that the floating point value should be 37 either infinity, negative infinity, or not-a-number respectively. 38 !*/ 39 float_detailsfloat_details40 float_details( 41 int64 man, 42 int16 exp 43 ) : mantissa(man), exponent(exp) {} 44 /*! 45 ensures 46 - #mantissa == man 47 - #exponent == exp 48 !*/ 49 float_detailsfloat_details50 float_details() : 51 mantissa(0), exponent(0) 52 {} 53 /*! 54 ensures 55 - this object represents a floating point value of 0 56 !*/ 57 float_detailsfloat_details58 float_details ( const double& val) { *this = val; } float_detailsfloat_details59 float_details ( const float& val) { *this = val; } float_detailsfloat_details60 float_details ( const long double& val) { *this = val; } 61 /*! 62 ensures 63 - converts the given value into a float_details representation. This 64 means that converting #*this back into a floating point number should 65 recover the input val. 66 !*/ 67 68 float_details& operator= ( const double& val) { convert_from_T(val); return *this; } 69 float_details& operator= ( const float& val) { convert_from_T(val); return *this; } 70 float_details& operator= ( const long double& val) { convert_from_T(val); return *this; } 71 /*! 72 ensures 73 - converts the given value into a float_details representation. This 74 means that converting #*this back into a floating point number should 75 recover the input val. 76 !*/ 77 78 operator double () const { return convert_to_T<double>(); } 79 operator float () const { return convert_to_T<float>(); } 80 operator long double () const { return convert_to_T<long double>(); } 81 /*! 82 ensures 83 - converts the contents of this float_details object into a floating point number. 84 !*/ 85 86 const static int16 is_inf = 32000; 87 const static int16 is_ninf = 32001; 88 const static int16 is_nan = 32002; 89 90 int64 mantissa; 91 int16 exponent; 92 93 94 private: 95 96 97 // ---------------------------------------------------------------------------------------- 98 // ---------------------------------------------------------------------------------------- 99 // IMPLEMENTATION DETAILS 100 // ---------------------------------------------------------------------------------------- 101 // ---------------------------------------------------------------------------------------- 102 103 template <typename T> convert_from_Tfloat_details104 void convert_from_T ( 105 const T& val 106 ) 107 { 108 mantissa = 0; 109 110 const int digits = dlib::tmin<std::numeric_limits<T>::digits, 63>::value; 111 112 if (val == std::numeric_limits<T>::infinity()) 113 { 114 exponent = is_inf; 115 } 116 else if (val == -std::numeric_limits<T>::infinity()) 117 { 118 exponent = is_ninf; 119 } 120 else if (val < std::numeric_limits<T>::infinity()) 121 { 122 int exp; 123 mantissa = static_cast<int64>(std::frexp(val, &exp)*(((uint64)1)<<digits)); 124 exponent = exp - digits; 125 126 // Compact the representation a bit by shifting off any low order bytes 127 // which are zero in the mantissa. This makes the numbers in mantissa and 128 // exponent generally smaller which can make serialization and other things 129 // more efficient in some cases. 130 for (int i = 0; i < 8 && ((mantissa&0xFF)==0); ++i) 131 { 132 mantissa >>= 8; 133 exponent += 8; 134 } 135 } 136 else 137 { 138 exponent = is_nan; 139 } 140 } 141 142 template <typename T> convert_to_Tfloat_details143 T convert_to_T ( 144 ) const 145 { 146 if (exponent < is_inf) 147 return std::ldexp((T)mantissa, exponent); 148 else if (exponent == is_inf) 149 return std::numeric_limits<T>::infinity(); 150 else if (exponent == is_ninf) 151 return -std::numeric_limits<T>::infinity(); 152 else 153 return std::numeric_limits<T>::quiet_NaN(); 154 } 155 156 }; 157 158 } 159 160 #endif // DLIB_FLOAT_DEtAILS_Hh_ 161 162