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