arm_compute v18.05
[platform/upstream/armcl.git] / include / half / README.txt
1 HALF-PRECISION FLOATING POINT LIBRARY (Version 1.12.0)\r
2 ------------------------------------------------------\r
3 \r
4 This is a C++ header-only library to provide an IEEE 754 conformant 16-bit \r
5 half-precision floating point type along with corresponding arithmetic \r
6 operators, type conversions and common mathematical functions. It aims for both \r
7 efficiency and ease of use, trying to accurately mimic the behaviour of the \r
8 builtin floating point types at the best performance possible.\r
9 \r
10 \r
11 INSTALLATION AND REQUIREMENTS\r
12 -----------------------------\r
13 \r
14 Comfortably enough, the library consists of just a single header file \r
15 containing all the functionality, which can be directly included by your \r
16 projects, without the neccessity to build anything or link to anything.\r
17 \r
18 Whereas this library is fully C++98-compatible, it can profit from certain \r
19 C++11 features. Support for those features is checked automatically at compile \r
20 (or rather preprocessing) time, but can be explicitly enabled or disabled by \r
21 defining the corresponding preprocessor symbols to either 1 or 0 yourself. This \r
22 is useful when the automatic detection fails (for more exotic implementations) \r
23 or when a feature should be explicitly disabled:\r
24 \r
25   - 'long long' integer type for mathematical functions returning 'long long' \r
26     results (enabled for VC++ 2003 and newer, gcc and clang, overridable with \r
27     'HALF_ENABLE_CPP11_LONG_LONG').\r
28 \r
29   - Static assertions for extended compile-time checks (enabled for VC++ 2010, \r
30     gcc 4.3, clang 2.9 and newer, overridable with 'HALF_ENABLE_CPP11_STATIC_ASSERT').\r
31 \r
32   - Generalized constant expressions (enabled for VC++ 2015, gcc 4.6, clang 3.1 \r
33     and newer, overridable with 'HALF_ENABLE_CPP11_CONSTEXPR').\r
34 \r
35   - noexcept exception specifications (enabled for VC++ 2015, gcc 4.6, clang 3.0 \r
36     and newer, overridable with 'HALF_ENABLE_CPP11_NOEXCEPT').\r
37 \r
38   - User-defined literals for half-precision literals to work (enabled for \r
39     VC++ 2015, gcc 4.7, clang 3.1 and newer, overridable with \r
40     'HALF_ENABLE_CPP11_USER_LITERALS').\r
41 \r
42   - Type traits and template meta-programming features from <type_traits> \r
43     (enabled for VC++ 2010, libstdc++ 4.3, libc++ and newer, overridable with \r
44     'HALF_ENABLE_CPP11_TYPE_TRAITS').\r
45 \r
46   - Special integer types from <cstdint> (enabled for VC++ 2010, libstdc++ 4.3, \r
47     libc++ and newer, overridable with 'HALF_ENABLE_CPP11_CSTDINT').\r
48 \r
49   - Certain C++11 single-precision mathematical functions from <cmath> for \r
50     an improved implementation of their half-precision counterparts to work \r
51     (enabled for VC++ 2013, libstdc++ 4.3, libc++ and newer, overridable with \r
52     'HALF_ENABLE_CPP11_CMATH').\r
53 \r
54   - Hash functor 'std::hash' from <functional> (enabled for VC++ 2010, \r
55     libstdc++ 4.3, libc++ and newer, overridable with 'HALF_ENABLE_CPP11_HASH').\r
56 \r
57 The library has been tested successfully with Visual C++ 2005-2015, gcc 4.4-4.8 \r
58 and clang 3.1. Please contact me if you have any problems, suggestions or even \r
59 just success testing it on other platforms.\r
60 \r
61 \r
62 DOCUMENTATION\r
63 -------------\r
64 \r
65 Here follow some general words about the usage of the library and its \r
66 implementation. For a complete documentation of its iterface look at the \r
67 corresponding website http://half.sourceforge.net. You may also generate the \r
68 complete developer documentation from the library's only include file's doxygen \r
69 comments, but this is more relevant to developers rather than mere users (for \r
70 reasons described below).\r
71 \r
72 BASIC USAGE\r
73 \r
74 To make use of the library just include its only header file half.hpp, which \r
75 defines all half-precision functionality inside the 'half_float' namespace. The \r
76 actual 16-bit half-precision data type is represented by the 'half' type. This \r
77 type behaves like the builtin floating point types as much as possible, \r
78 supporting the usual arithmetic, comparison and streaming operators, which \r
79 makes its use pretty straight-forward:\r
80 \r
81     using half_float::half;\r
82     half a(3.4), b(5);\r
83     half c = a * b;\r
84     c += 3;\r
85     if(c > a)\r
86             std::cout << c << std::endl;\r
87 \r
88 Additionally the 'half_float' namespace also defines half-precision versions \r
89 for all mathematical functions of the C++ standard library, which can be used \r
90 directly through ADL:\r
91 \r
92     half a(-3.14159);\r
93     half s = sin(abs(a));\r
94     long l = lround(s);\r
95 \r
96 You may also specify explicit half-precision literals, since the library \r
97 provides a user-defined literal inside the 'half_float::literal' namespace, \r
98 which you just need to import (assuming support for C++11 user-defined literals):\r
99 \r
100     using namespace half_float::literal;\r
101     half x = 1.0_h;\r
102 \r
103 Furthermore the library provides proper specializations for \r
104 'std::numeric_limits', defining various implementation properties, and \r
105 'std::hash' for hashing half-precision numbers (assuming support for C++11 \r
106 'std::hash'). Similar to the corresponding preprocessor symbols from <cmath> \r
107 the library also defines the 'HUGE_VALH' constant and maybe the 'FP_FAST_FMAH' \r
108 symbol.\r
109 \r
110 CONVERSIONS AND ROUNDING\r
111 \r
112 The half is explicitly constructible/convertible from a single-precision float \r
113 argument. Thus it is also explicitly constructible/convertible from any type \r
114 implicitly convertible to float, but constructing it from types like double or \r
115 int will involve the usual warnings arising when implicitly converting those to \r
116 float because of the lost precision. On the one hand those warnings are \r
117 intentional, because converting those types to half neccessarily also reduces \r
118 precision. But on the other hand they are raised for explicit conversions from \r
119 those types, when the user knows what he is doing. So if those warnings keep \r
120 bugging you, then you won't get around first explicitly converting to float \r
121 before converting to half, or use the 'half_cast' described below. In addition \r
122 you can also directly assign float values to halfs.\r
123 \r
124 In contrast to the float-to-half conversion, which reduces precision, the \r
125 conversion from half to float (and thus to any other type implicitly \r
126 convertible from float) is implicit, because all values represetable with \r
127 half-precision are also representable with single-precision. This way the \r
128 half-to-float conversion behaves similar to the builtin float-to-double \r
129 conversion and all arithmetic expressions involving both half-precision and \r
130 single-precision arguments will be of single-precision type. This way you can \r
131 also directly use the mathematical functions of the C++ standard library, \r
132 though in this case you will invoke the single-precision versions which will \r
133 also return single-precision values, which is (even if maybe performing the \r
134 exact same computation, see below) not as conceptually clean when working in a \r
135 half-precision environment.\r
136 \r
137 The default rounding mode for conversions from float to half uses truncation \r
138 (round toward zero, but mapping overflows to infinity) for rounding values not \r
139 representable exactly in half-precision. This is the fastest rounding possible \r
140 and is usually sufficient. But by redefining the 'HALF_ROUND_STYLE' \r
141 preprocessor symbol (before including half.hpp) this default can be overridden \r
142 with one of the other standard rounding modes using their respective constants \r
143 or the equivalent values of 'std::float_round_style' (it can even be \r
144 synchronized with the underlying single-precision implementation by defining it \r
145 to 'std::numeric_limits<float>::round_style'):\r
146 \r
147   - 'std::round_indeterminate' or -1 for the fastest rounding (default).\r
148 \r
149   - 'std::round_toward_zero' or 0 for rounding toward zero.\r
150 \r
151   - std::round_to_nearest' or 1 for rounding to the nearest value.\r
152 \r
153   - std::round_toward_infinity' or 2 for rounding toward positive infinity.\r
154 \r
155   - std::round_toward_neg_infinity' or 3 for rounding toward negative infinity.\r
156 \r
157 In addition to changing the overall default rounding mode one can also use the \r
158 'half_cast'. This converts between half and any built-in arithmetic type using \r
159 a configurable rounding mode (or the default rounding mode if none is \r
160 specified). In addition to a configurable rounding mode, 'half_cast' has \r
161 another big difference to a mere 'static_cast': Any conversions are performed \r
162 directly using the given rounding mode, without any intermediate conversion \r
163 to/from 'float'. This is especially relevant for conversions to integer types, \r
164 which don't necessarily truncate anymore. But also for conversions from \r
165 'double' or 'long double' this may produce more precise results than a \r
166 pre-conversion to 'float' using the single-precision implementation's current \r
167 rounding mode would.\r
168 \r
169     half a = half_cast<half>(4.2);\r
170     half b = half_cast<half,std::numeric_limits<float>::round_style>(4.2f);\r
171     assert( half_cast<int, std::round_to_nearest>( 0.7_h )     == 1 );\r
172     assert( half_cast<half,std::round_toward_zero>( 4097 )     == 4096.0_h );\r
173     assert( half_cast<half,std::round_toward_infinity>( 4097 ) == 4100.0_h );\r
174     assert( half_cast<half,std::round_toward_infinity>( std::numeric_limits<double>::min() ) > 0.0_h );\r
175 \r
176 When using round to nearest (either as default or through 'half_cast') ties are \r
177 by default resolved by rounding them away from zero (and thus equal to the \r
178 behaviour of the 'round' function). But by redefining the \r
179 'HALF_ROUND_TIES_TO_EVEN' preprocessor symbol to 1 (before including half.hpp) \r
180 this default can be changed to the slightly slower but less biased and more \r
181 IEEE-conformant behaviour of rounding half-way cases to the nearest even value.\r
182 \r
183     #define HALF_ROUND_TIES_TO_EVEN 1\r
184     #include <half.hpp>\r
185     ...\r
186     assert( half_cast<int,std::round_to_nearest>(3.5_h) \r
187          == half_cast<int,std::round_to_nearest>(4.5_h) );\r
188 \r
189 IMPLEMENTATION\r
190 \r
191 For performance reasons (and ease of implementation) many of the mathematical \r
192 functions provided by the library as well as all arithmetic operations are \r
193 actually carried out in single-precision under the hood, calling to the C++ \r
194 standard library implementations of those functions whenever appropriate, \r
195 meaning the arguments are converted to floats and the result back to half. But \r
196 to reduce the conversion overhead as much as possible any temporary values \r
197 inside of lengthy expressions are kept in single-precision as long as possible, \r
198 while still maintaining a strong half-precision type to the outside world. Only \r
199 when finally assigning the value to a half or calling a function that works \r
200 directly on halfs is the actual conversion done (or never, when further \r
201 converting the result to float.\r
202 \r
203 This approach has two implications. First of all you have to treat the \r
204 library's documentation at http://half.sourceforge.net as a simplified version, \r
205 describing the behaviour of the library as if implemented this way. The actual \r
206 argument and return types of functions and operators may involve other internal \r
207 types (feel free to generate the exact developer documentation from the Doxygen \r
208 comments in the library's header file if you really need to). But nevertheless \r
209 the behaviour is exactly like specified in the documentation. The other \r
210 implication is, that in the presence of rounding errors or over-/underflows \r
211 arithmetic expressions may produce different results when compared to \r
212 converting to half-precision after each individual operation:\r
213 \r
214     half a = std::numeric_limits<half>::max() * 2.0_h / 2.0_h;       // a = MAX\r
215     half b = half(std::numeric_limits<half>::max() * 2.0_h) / 2.0_h; // b = INF\r
216     assert( a != b );\r
217 \r
218 But this should only be a problem in very few cases. One last word has to be \r
219 said when talking about performance. Even with its efforts in reducing \r
220 conversion overhead as much as possible, the software half-precision \r
221 implementation can most probably not beat the direct use of single-precision \r
222 computations. Usually using actual float values for all computations and \r
223 temproraries and using halfs only for storage is the recommended way. On the \r
224 one hand this somehow makes the provided mathematical functions obsolete \r
225 (especially in light of the implicit conversion from half to float), but \r
226 nevertheless the goal of this library was to provide a complete and \r
227 conceptually clean half-precision implementation, to which the standard \r
228 mathematical functions belong, even if usually not needed.\r
229 \r
230 IEEE CONFORMANCE\r
231 \r
232 The half type uses the standard IEEE representation with 1 sign bit, 5 exponent \r
233 bits and 10 mantissa bits (11 when counting the hidden bit). It supports all \r
234 types of special values, like subnormal values, infinity and NaNs. But there \r
235 are some limitations to the complete conformance to the IEEE 754 standard:\r
236 \r
237   - The implementation does not differentiate between signalling and quiet \r
238     NaNs, this means operations on halfs are not specified to trap on \r
239     signalling NaNs (though they may, see last point).\r
240 \r
241   - Though arithmetic operations are internally rounded to single-precision \r
242     using the underlying single-precision implementation's current rounding \r
243     mode, those values are then converted to half-precision using the default \r
244     half-precision rounding mode (changed by defining 'HALF_ROUND_STYLE' \r
245     accordingly). This mixture of rounding modes is also the reason why \r
246     'std::numeric_limits<half>::round_style' may actually return \r
247     'std::round_indeterminate' when half- and single-precision rounding modes \r
248     don't match.\r
249 \r
250   - Because of internal truncation it may also be that certain single-precision \r
251     NaNs will be wrongly converted to half-precision infinity, though this is \r
252     very unlikely to happen, since most single-precision implementations don't \r
253     tend to only set the lowest bits of a NaN mantissa.\r
254 \r
255   - The implementation does not provide any floating point exceptions, thus \r
256     arithmetic operations or mathematical functions are not specified to invoke \r
257     proper floating point exceptions. But due to many functions implemented in \r
258     single-precision, those may still invoke floating point exceptions of the \r
259     underlying single-precision implementation.\r
260 \r
261 Some of those points could have been circumvented by controlling the floating \r
262 point environment using <cfenv> or implementing a similar exception mechanism. \r
263 But this would have required excessive runtime checks giving two high an impact \r
264 on performance for something that is rarely ever needed. If you really need to \r
265 rely on proper floating point exceptions, it is recommended to explicitly \r
266 perform computations using the built-in floating point types to be on the safe \r
267 side. In the same way, if you really need to rely on a particular rounding \r
268 behaviour, it is recommended to either use single-precision computations and \r
269 explicitly convert the result to half-precision using 'half_cast' and \r
270 specifying the desired rounding mode, or synchronize the default half-precision \r
271 rounding mode to the rounding mode of the single-precision implementation (most \r
272 likely 'HALF_ROUND_STYLE=1', 'HALF_ROUND_TIES_TO_EVEN=1'). But this is really \r
273 considered an expert-scenario that should be used only when necessary, since \r
274 actually working with half-precision usually comes with a certain \r
275 tolerance/ignorance of exactness considerations and proper rounding comes with \r
276 a certain performance cost.\r
277 \r
278 \r
279 CREDITS AND CONTACT\r
280 -------------------\r
281 \r
282 This library is developed by CHRISTIAN RAU and released under the MIT License \r
283 (see LICENSE.txt). If you have any questions or problems with it, feel free to \r
284 contact me at rauy@users.sourceforge.net.\r
285 \r
286 Additional credit goes to JEROEN VAN DER ZIJP for his paper on "Fast Half Float \r
287 Conversions", whose algorithms have been used in the library for converting \r
288 between half-precision and single-precision values.\r