├── .azuredevops └── rocm-ci.yml ├── .github ├── CODEOWNERS └── dependabot.yml ├── .readthedocs.yaml ├── CMakeLists.txt ├── ChangeLog.txt ├── LICENSE.txt ├── README.txt ├── docs ├── .gitignore ├── conf.py ├── doxygen │ └── Doxyfile ├── index.rst ├── license.rst └── sphinx │ ├── _toc.yml.in │ ├── requirements.in │ └── requirements.txt ├── half.sln ├── half.vcxproj ├── half.vcxproj.filters ├── include └── half.hpp ├── test ├── Makefile ├── projects │ ├── vs2005 │ │ ├── test.sln │ │ └── test.vcproj │ ├── vs2008 │ │ ├── test.sln │ │ └── test.vcproj │ ├── vs2010 │ │ ├── test.sln │ │ ├── test.vcxproj │ │ └── test.vcxproj.filters │ ├── vs2012 │ │ ├── test.sln │ │ ├── test.vcxproj │ │ └── test.vcxproj.filters │ ├── vs2013 │ │ ├── test.sln │ │ ├── test.vcxproj │ │ └── test.vcxproj.filters │ └── vs2015 │ │ ├── test.sln │ │ ├── test.vcxproj │ │ └── test.vcxproj.filters └── src │ ├── test03.cpp │ └── test11.cpp └── web ├── Doxyfile ├── Mainpage.md ├── News.md ├── half.hpp ├── layout.xml ├── web.vcxproj └── web.vcxproj.filters /.azuredevops/rocm-ci.yml: -------------------------------------------------------------------------------- 1 | resources: 2 | repositories: 3 | - repository: pipelines_repo 4 | type: github 5 | endpoint: ROCm 6 | name: ROCm/ROCm 7 | 8 | variables: 9 | - group: common 10 | - template: /.azuredevops/variables-global.yml@pipelines_repo 11 | 12 | trigger: 13 | batch: true 14 | branches: 15 | include: 16 | - rocm 17 | paths: 18 | exclude: 19 | - .github 20 | - docs 21 | - '.*.y*ml' 22 | - LICENSE.txt 23 | - README.txt 24 | 25 | pr: 26 | autoCancel: true 27 | branches: 28 | include: 29 | - rocm 30 | paths: 31 | exclude: 32 | - .github 33 | - docs 34 | - '.*.y*ml' 35 | - LICENSE.txt 36 | - README.txt 37 | drafts: false 38 | 39 | jobs: 40 | - template: ${{ variables.CI_COMPONENT_PATH }}/half.yml@pipelines_repo 41 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | **/CMakeLists.txt @pfultz2 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/docs/sphinx" # Location of package manifests 10 | open-pull-requests-limit: 10 11 | schedule: 12 | interval: "daily" 13 | target-branch: "develop" 14 | labels: 15 | - "documentation" 16 | - "dependencies" 17 | reviewers: 18 | - "samjwu" 19 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | version: 2 5 | 6 | sphinx: 7 | configuration: docs/conf.py 8 | 9 | formats: [htmlzip, pdf, epub] 10 | 11 | python: 12 | install: 13 | - requirements: docs/sphinx/requirements.txt 14 | 15 | build: 16 | os: ubuntu-22.04 17 | tools: 18 | python: "3.10" 19 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | # This has to be initialized before the project() command appears 4 | # Set the default of CMAKE_BUILD_TYPE to be release, unless user specifies with -D. MSVC_IDE does not use CMAKE_BUILD_TYPE 5 | if( NOT MSVC_IDE AND NOT CMAKE_BUILD_TYPE ) 6 | set( CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." ) 7 | endif() 8 | 9 | # Default installation path 10 | if(WIN32) 11 | set(CMAKE_INSTALL_PREFIX "/opt/rocm/x86_64-w64-mingw32" CACHE PATH "") 12 | else() 13 | set(CMAKE_INSTALL_PREFIX "/opt/rocm" CACHE PATH "") 14 | endif() 15 | 16 | project(half) 17 | find_package(ROCM REQUIRED) 18 | 19 | include(ROCMSetupVersion) 20 | include(ROCMCreatePackage) 21 | 22 | # FOR HANDLING ENABLE/DISABLE OPTIONAL BACKWARD COMPATIBILITY for FILE/FOLDER REORG 23 | option(BUILD_FILE_REORG_BACKWARD_COMPATIBILITY "Build with file/folder reorg with backward compatibility enabled" OFF) 24 | 25 | rocm_setup_version(VERSION 1.12.0 NO_GIT_TAG_VERSION) 26 | 27 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/half.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/half) 28 | 29 | if(BUILD_FILE_REORG_BACKWARD_COMPATIBILITY) 30 | include(ROCMHeaderWrapper) 31 | rocm_wrap_header_file( 32 | half.hpp 33 | GUARDS WRAPPER 34 | WRAPPER_LOCATIONS ${CMAKE_INSTALL_INCLUDEDIR} 35 | ) 36 | 37 | #Install Wrapper for backward compatibility 38 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR}/half.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 39 | endif() 40 | 41 | rocm_create_package( 42 | NAME half 43 | DESCRIPTION "HALF-PRECISION FLOATING POINT LIBRARY" 44 | MAINTAINER "Paul Fultz II " 45 | ) 46 | -------------------------------------------------------------------------------- /ChangeLog.txt: -------------------------------------------------------------------------------- 1 | Release Notes {#changelog} 2 | ============= 3 | 4 | 1.12.0 release (2017-03-06): 5 | ---------------------------- 6 | 7 | - Changed behaviour of `half_cast` to perform conversions to/from `double` 8 | and `long double` directly according to specified rounding mode, without an 9 | intermediate `float` conversion. 10 | - Added `noexcept` specifiers to constructors. 11 | - Fixed minor portability problem with `logb` and `ilogb`. 12 | - Tested for *VC++ 2015*. 13 | 14 | 15 | 1.11.0 release (2013-11-16): 16 | ---------------------------- 17 | 18 | - Made tie-breaking behaviour in round to nearest configurable by 19 | `HALF_ROUND_TIES_TO_EVEN` macro. 20 | - Completed support for all C++11 mathematical functions even if single- 21 | precision versions from `` are unsupported. 22 | - Fixed inability to disable support for C++11 mathematical functions on 23 | *VC++ 2013*. 24 | 25 | 26 | 1.10.0 release (2013-11-09): 27 | ---------------------------- 28 | 29 | - Made default rounding mode configurable by `HALF_ROUND_STYLE` macro. 30 | - Added support for non-IEEE single-precision implementations. 31 | - Added `HALF_ENABLE_CPP11_TYPE_TRAITS` preprocessor flag for checking 32 | support for C++11 type traits and TMP features. 33 | - Restricted `half_cast` to support built-in arithmetic types only. 34 | - Changed behaviour of `half_cast` to respect rounding mode when casting 35 | to/from integer types. 36 | 37 | 38 | 1.9.2 release (2013-11-01): 39 | --------------------------- 40 | 41 | - Tested for *gcc 4.8*. 42 | - Tested and fixed for *VC++ 2013*. 43 | - Removed unnecessary warnings in *MSVC*. 44 | 45 | 46 | 1.9.1 release (2013-08-08): 47 | --------------------------- 48 | 49 | - Fixed problems with older gcc and MSVC versions. 50 | - Small fix to non-C++11 implementations of `remainder` and `remquo`. 51 | 52 | 53 | 1.9.0 release (2013-08-07): 54 | --------------------------- 55 | 56 | - Changed behaviour of `nearbyint`, `rint`, `lrint` and `llrint` to use 57 | rounding mode of half-precision implementation (which is 58 | truncating/indeterminate) instead of single-precision rounding mode. 59 | - Added support for more C++11 mathematical functions even if single- 60 | precision versions from `` are unsupported, in particular 61 | `remainder`, `remquo` and `cbrt`. 62 | - Minor implementation changes. 63 | 64 | 65 | 1.8.1 release (2013-01-22): 66 | --------------------------- 67 | 68 | - Fixed bug resulting in multiple definitions of the `nanh` function due to 69 | a missing `inline` specification. 70 | 71 | 72 | 1.8.0 release (2013-01-19): 73 | --------------------------- 74 | 75 | - Added support for more C++11 mathematical functions even if single- 76 | precision versions from `` are unsupported, in particular 77 | exponential and logarithm functions, hyperbolic area functions and the 78 | hypotenuse function. 79 | - Made `fma` function use default implementation if single-precision version 80 | from `` is not faster and thus `FP_FAST_FMAH` to be defined always. 81 | - Fixed overload resolution issues when invoking certain mathematical 82 | functions by unqualified calls. 83 | 84 | 85 | 1.7.0 release (2012-10-26): 86 | --------------------------- 87 | 88 | - Added support for C++11 `noexcept` specifiers. 89 | - Changed C++11 `long long` to be supported on *VC++ 2003* and up. 90 | 91 | 92 | 1.6.1 release (2012-09-13): 93 | --------------------------- 94 | 95 | - Made `fma` and `fdim` functions available even if corresponding 96 | single-precision functions are not. 97 | 98 | 99 | 1.6.0 release (2012-09-12): 100 | --------------------------- 101 | 102 | - Added `HALF_ENABLE_CPP11_LONG_LONG` to control support for `long long` 103 | integers and corresponding mathematical functions. 104 | - Fixed C++98 compatibility on non-VC compilers. 105 | 106 | 107 | 1.5.1 release (2012-08-17): 108 | --------------------------- 109 | 110 | - Recorrected `std::numeric_limits::round_style` to always return 111 | `std::round_indeterminate`, due to overflow-handling deviating from 112 | correct round-toward-zero behaviour. 113 | 114 | 115 | 1.5.0 release (2012-08-16): 116 | --------------------------- 117 | 118 | - Added `half_cast` for explicitly casting between half and any type 119 | convertible to/from `float` and allowing the explicit specification of 120 | the rounding mode to use. 121 | 122 | 123 | 1.4.0 release (2012-08-12): 124 | --------------------------- 125 | 126 | - Added support for C++11 generalized constant expressions (`constexpr`). 127 | 128 | 129 | 1.3.1 release (2012-08-11): 130 | --------------------------- 131 | 132 | - Fixed requirement for `std::signbit` and `std::isnan` (even if C++11 133 | `` functions disabled) on non-VC compilers. 134 | 135 | 136 | 1.3.0 release (2012-08-10): 137 | --------------------------- 138 | 139 | - Made requirement for `` and `static_assert` optional and thus 140 | made the library C++98-compatible. 141 | - Made support for C++11 features user-overridable through explicit 142 | definition of corresponding preprocessor symbols to either 0 or 1. 143 | - Renamed `HALF_ENABLE_HASH` to `HALF_ENABLE_CPP11_HASH` in correspondence 144 | with other C++11 preprocessor symbols. 145 | 146 | 147 | 1.2.0 release (2012-08-07): 148 | --------------------------- 149 | 150 | - Added proper preprocessor definitions for `HUGE_VALH` and `FP_FAST_FMAH` 151 | in correspondence with their single-precision counterparts from ``. 152 | - Fixed internal preprocessor macros to be properly undefined after use. 153 | 154 | 155 | 1.1.2 release (2012-08-07): 156 | --------------------------- 157 | 158 | - Revised `std::numeric_limits::round_style` to return 159 | `std::round_toward_zero` if the `float` version also does and 160 | `std::round_indeterminate` otherwise. 161 | - Fixed `std::numeric_limits::round_error` to reflect worst-case round 162 | toward zero behaviour. 163 | 164 | 165 | 1.1.1 release (2012-08-06): 166 | --------------------------- 167 | 168 | - Fixed `std::numeric_limits::min` to return smallest positive normal 169 | number, instead of subnormal number. 170 | - Fixed `std::numeric_limits::round_style` to return 171 | `std::round_indeterminate` due to mixture of separately rounded 172 | single-precision arithmetics with truncating single-to-half conversions. 173 | 174 | 175 | 1.1.0 release (2012-08-06): 176 | --------------------------- 177 | 178 | - Added half-precision literals. 179 | 180 | 181 | 1.0.0 release (2012-08-05): 182 | --------------------------- 183 | 184 | - First release. 185 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2012-2017 Christian Rau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | HALF-PRECISION FLOATING POINT LIBRARY (Version 1.12.0) 2 | ------------------------------------------------------ 3 | 4 | This is a C++ header-only library to provide an IEEE 754 conformant 16-bit 5 | half-precision floating point type along with corresponding arithmetic 6 | operators, type conversions and common mathematical functions. It aims for both 7 | efficiency and ease of use, trying to accurately mimic the behaviour of the 8 | builtin floating point types at the best performance possible. 9 | 10 | 11 | INSTALLATION AND REQUIREMENTS 12 | ----------------------------- 13 | 14 | Comfortably enough, the library consists of just a single header file 15 | containing all the functionality, which can be directly included by your 16 | projects, without the neccessity to build anything or link to anything. 17 | 18 | Whereas this library is fully C++98-compatible, it can profit from certain 19 | C++11 features. Support for those features is checked automatically at compile 20 | (or rather preprocessing) time, but can be explicitly enabled or disabled by 21 | defining the corresponding preprocessor symbols to either 1 or 0 yourself. This 22 | is useful when the automatic detection fails (for more exotic implementations) 23 | or when a feature should be explicitly disabled: 24 | 25 | - 'long long' integer type for mathematical functions returning 'long long' 26 | results (enabled for VC++ 2003 and newer, gcc and clang, overridable with 27 | 'HALF_ENABLE_CPP11_LONG_LONG'). 28 | 29 | - Static assertions for extended compile-time checks (enabled for VC++ 2010, 30 | gcc 4.3, clang 2.9 and newer, overridable with 'HALF_ENABLE_CPP11_STATIC_ASSERT'). 31 | 32 | - Generalized constant expressions (enabled for VC++ 2015, gcc 4.6, clang 3.1 33 | and newer, overridable with 'HALF_ENABLE_CPP11_CONSTEXPR'). 34 | 35 | - noexcept exception specifications (enabled for VC++ 2015, gcc 4.6, clang 3.0 36 | and newer, overridable with 'HALF_ENABLE_CPP11_NOEXCEPT'). 37 | 38 | - User-defined literals for half-precision literals to work (enabled for 39 | VC++ 2015, gcc 4.7, clang 3.1 and newer, overridable with 40 | 'HALF_ENABLE_CPP11_USER_LITERALS'). 41 | 42 | - Type traits and template meta-programming features from 43 | (enabled for VC++ 2010, libstdc++ 4.3, libc++ and newer, overridable with 44 | 'HALF_ENABLE_CPP11_TYPE_TRAITS'). 45 | 46 | - Special integer types from (enabled for VC++ 2010, libstdc++ 4.3, 47 | libc++ and newer, overridable with 'HALF_ENABLE_CPP11_CSTDINT'). 48 | 49 | - Certain C++11 single-precision mathematical functions from for 50 | an improved implementation of their half-precision counterparts to work 51 | (enabled for VC++ 2013, libstdc++ 4.3, libc++ and newer, overridable with 52 | 'HALF_ENABLE_CPP11_CMATH'). 53 | 54 | - Hash functor 'std::hash' from (enabled for VC++ 2010, 55 | libstdc++ 4.3, libc++ and newer, overridable with 'HALF_ENABLE_CPP11_HASH'). 56 | 57 | The library has been tested successfully with Visual C++ 2005-2015, gcc 4.4-4.8 58 | and clang 3.1. Please contact me if you have any problems, suggestions or even 59 | just success testing it on other platforms. 60 | 61 | 62 | DOCUMENTATION 63 | ------------- 64 | 65 | Here follow some general words about the usage of the library and its 66 | implementation. For a complete documentation of its iterface look at the 67 | corresponding website http://half.sourceforge.net. You may also generate the 68 | complete developer documentation from the library's only include file's doxygen 69 | comments, but this is more relevant to developers rather than mere users (for 70 | reasons described below). 71 | 72 | BASIC USAGE 73 | 74 | To make use of the library just include its only header file half.hpp, which 75 | defines all half-precision functionality inside the 'half_float' namespace. The 76 | actual 16-bit half-precision data type is represented by the 'half' type. This 77 | type behaves like the builtin floating point types as much as possible, 78 | supporting the usual arithmetic, comparison and streaming operators, which 79 | makes its use pretty straight-forward: 80 | 81 | using half_float::half; 82 | half a(3.4), b(5); 83 | half c = a * b; 84 | c += 3; 85 | if(c > a) 86 | std::cout << c << std::endl; 87 | 88 | Additionally the 'half_float' namespace also defines half-precision versions 89 | for all mathematical functions of the C++ standard library, which can be used 90 | directly through ADL: 91 | 92 | half a(-3.14159); 93 | half s = sin(abs(a)); 94 | long l = lround(s); 95 | 96 | You may also specify explicit half-precision literals, since the library 97 | provides a user-defined literal inside the 'half_float::literal' namespace, 98 | which you just need to import (assuming support for C++11 user-defined literals): 99 | 100 | using namespace half_float::literal; 101 | half x = 1.0_h; 102 | 103 | Furthermore the library provides proper specializations for 104 | 'std::numeric_limits', defining various implementation properties, and 105 | 'std::hash' for hashing half-precision numbers (assuming support for C++11 106 | 'std::hash'). Similar to the corresponding preprocessor symbols from 107 | the library also defines the 'HUGE_VALH' constant and maybe the 'FP_FAST_FMAH' 108 | symbol. 109 | 110 | CONVERSIONS AND ROUNDING 111 | 112 | The half is explicitly constructible/convertible from a single-precision float 113 | argument. Thus it is also explicitly constructible/convertible from any type 114 | implicitly convertible to float, but constructing it from types like double or 115 | int will involve the usual warnings arising when implicitly converting those to 116 | float because of the lost precision. On the one hand those warnings are 117 | intentional, because converting those types to half neccessarily also reduces 118 | precision. But on the other hand they are raised for explicit conversions from 119 | those types, when the user knows what he is doing. So if those warnings keep 120 | bugging you, then you won't get around first explicitly converting to float 121 | before converting to half, or use the 'half_cast' described below. In addition 122 | you can also directly assign float values to halfs. 123 | 124 | In contrast to the float-to-half conversion, which reduces precision, the 125 | conversion from half to float (and thus to any other type implicitly 126 | convertible from float) is implicit, because all values represetable with 127 | half-precision are also representable with single-precision. This way the 128 | half-to-float conversion behaves similar to the builtin float-to-double 129 | conversion and all arithmetic expressions involving both half-precision and 130 | single-precision arguments will be of single-precision type. This way you can 131 | also directly use the mathematical functions of the C++ standard library, 132 | though in this case you will invoke the single-precision versions which will 133 | also return single-precision values, which is (even if maybe performing the 134 | exact same computation, see below) not as conceptually clean when working in a 135 | half-precision environment. 136 | 137 | The default rounding mode for conversions from float to half uses truncation 138 | (round toward zero, but mapping overflows to infinity) for rounding values not 139 | representable exactly in half-precision. This is the fastest rounding possible 140 | and is usually sufficient. But by redefining the 'HALF_ROUND_STYLE' 141 | preprocessor symbol (before including half.hpp) this default can be overridden 142 | with one of the other standard rounding modes using their respective constants 143 | or the equivalent values of 'std::float_round_style' (it can even be 144 | synchronized with the underlying single-precision implementation by defining it 145 | to 'std::numeric_limits::round_style'): 146 | 147 | - 'std::round_indeterminate' or -1 for the fastest rounding (default). 148 | 149 | - 'std::round_toward_zero' or 0 for rounding toward zero. 150 | 151 | - std::round_to_nearest' or 1 for rounding to the nearest value. 152 | 153 | - std::round_toward_infinity' or 2 for rounding toward positive infinity. 154 | 155 | - std::round_toward_neg_infinity' or 3 for rounding toward negative infinity. 156 | 157 | In addition to changing the overall default rounding mode one can also use the 158 | 'half_cast'. This converts between half and any built-in arithmetic type using 159 | a configurable rounding mode (or the default rounding mode if none is 160 | specified). In addition to a configurable rounding mode, 'half_cast' has 161 | another big difference to a mere 'static_cast': Any conversions are performed 162 | directly using the given rounding mode, without any intermediate conversion 163 | to/from 'float'. This is especially relevant for conversions to integer types, 164 | which don't necessarily truncate anymore. But also for conversions from 165 | 'double' or 'long double' this may produce more precise results than a 166 | pre-conversion to 'float' using the single-precision implementation's current 167 | rounding mode would. 168 | 169 | half a = half_cast(4.2); 170 | half b = half_cast::round_style>(4.2f); 171 | assert( half_cast( 0.7_h ) == 1 ); 172 | assert( half_cast( 4097 ) == 4096.0_h ); 173 | assert( half_cast( 4097 ) == 4100.0_h ); 174 | assert( half_cast( std::numeric_limits::min() ) > 0.0_h ); 175 | 176 | When using round to nearest (either as default or through 'half_cast') ties are 177 | by default resolved by rounding them away from zero (and thus equal to the 178 | behaviour of the 'round' function). But by redefining the 179 | 'HALF_ROUND_TIES_TO_EVEN' preprocessor symbol to 1 (before including half.hpp) 180 | this default can be changed to the slightly slower but less biased and more 181 | IEEE-conformant behaviour of rounding half-way cases to the nearest even value. 182 | 183 | #define HALF_ROUND_TIES_TO_EVEN 1 184 | #include 185 | ... 186 | assert( half_cast(3.5_h) 187 | == half_cast(4.5_h) ); 188 | 189 | IMPLEMENTATION 190 | 191 | For performance reasons (and ease of implementation) many of the mathematical 192 | functions provided by the library as well as all arithmetic operations are 193 | actually carried out in single-precision under the hood, calling to the C++ 194 | standard library implementations of those functions whenever appropriate, 195 | meaning the arguments are converted to floats and the result back to half. But 196 | to reduce the conversion overhead as much as possible any temporary values 197 | inside of lengthy expressions are kept in single-precision as long as possible, 198 | while still maintaining a strong half-precision type to the outside world. Only 199 | when finally assigning the value to a half or calling a function that works 200 | directly on halfs is the actual conversion done (or never, when further 201 | converting the result to float. 202 | 203 | This approach has two implications. First of all you have to treat the 204 | library's documentation at http://half.sourceforge.net as a simplified version, 205 | describing the behaviour of the library as if implemented this way. The actual 206 | argument and return types of functions and operators may involve other internal 207 | types (feel free to generate the exact developer documentation from the Doxygen 208 | comments in the library's header file if you really need to). But nevertheless 209 | the behaviour is exactly like specified in the documentation. The other 210 | implication is, that in the presence of rounding errors or over-/underflows 211 | arithmetic expressions may produce different results when compared to 212 | converting to half-precision after each individual operation: 213 | 214 | half a = std::numeric_limits::max() * 2.0_h / 2.0_h; // a = MAX 215 | half b = half(std::numeric_limits::max() * 2.0_h) / 2.0_h; // b = INF 216 | assert( a != b ); 217 | 218 | But this should only be a problem in very few cases. One last word has to be 219 | said when talking about performance. Even with its efforts in reducing 220 | conversion overhead as much as possible, the software half-precision 221 | implementation can most probably not beat the direct use of single-precision 222 | computations. Usually using actual float values for all computations and 223 | temproraries and using halfs only for storage is the recommended way. On the 224 | one hand this somehow makes the provided mathematical functions obsolete 225 | (especially in light of the implicit conversion from half to float), but 226 | nevertheless the goal of this library was to provide a complete and 227 | conceptually clean half-precision implementation, to which the standard 228 | mathematical functions belong, even if usually not needed. 229 | 230 | IEEE CONFORMANCE 231 | 232 | The half type uses the standard IEEE representation with 1 sign bit, 5 exponent 233 | bits and 10 mantissa bits (11 when counting the hidden bit). It supports all 234 | types of special values, like subnormal values, infinity and NaNs. But there 235 | are some limitations to the complete conformance to the IEEE 754 standard: 236 | 237 | - The implementation does not differentiate between signalling and quiet 238 | NaNs, this means operations on halfs are not specified to trap on 239 | signalling NaNs (though they may, see last point). 240 | 241 | - Though arithmetic operations are internally rounded to single-precision 242 | using the underlying single-precision implementation's current rounding 243 | mode, those values are then converted to half-precision using the default 244 | half-precision rounding mode (changed by defining 'HALF_ROUND_STYLE' 245 | accordingly). This mixture of rounding modes is also the reason why 246 | 'std::numeric_limits::round_style' may actually return 247 | 'std::round_indeterminate' when half- and single-precision rounding modes 248 | don't match. 249 | 250 | - Because of internal truncation it may also be that certain single-precision 251 | NaNs will be wrongly converted to half-precision infinity, though this is 252 | very unlikely to happen, since most single-precision implementations don't 253 | tend to only set the lowest bits of a NaN mantissa. 254 | 255 | - The implementation does not provide any floating point exceptions, thus 256 | arithmetic operations or mathematical functions are not specified to invoke 257 | proper floating point exceptions. But due to many functions implemented in 258 | single-precision, those may still invoke floating point exceptions of the 259 | underlying single-precision implementation. 260 | 261 | Some of those points could have been circumvented by controlling the floating 262 | point environment using or implementing a similar exception mechanism. 263 | But this would have required excessive runtime checks giving two high an impact 264 | on performance for something that is rarely ever needed. If you really need to 265 | rely on proper floating point exceptions, it is recommended to explicitly 266 | perform computations using the built-in floating point types to be on the safe 267 | side. In the same way, if you really need to rely on a particular rounding 268 | behaviour, it is recommended to either use single-precision computations and 269 | explicitly convert the result to half-precision using 'half_cast' and 270 | specifying the desired rounding mode, or synchronize the default half-precision 271 | rounding mode to the rounding mode of the single-precision implementation (most 272 | likely 'HALF_ROUND_STYLE=1', 'HALF_ROUND_TIES_TO_EVEN=1'). But this is really 273 | considered an expert-scenario that should be used only when necessary, since 274 | actually working with half-precision usually comes with a certain 275 | tolerance/ignorance of exactness considerations and proper rounding comes with 276 | a certain performance cost. 277 | 278 | 279 | CREDITS AND CONTACT 280 | ------------------- 281 | 282 | This library is developed by CHRISTIAN RAU and released under the MIT License 283 | (see LICENSE.txt). If you have any questions or problems with it, feel free to 284 | contact me at rauy@users.sourceforge.net. 285 | 286 | Additional credit goes to JEROEN VAN DER ZIJP for his paper on "Fast Half Float 287 | Conversions", whose algorithms have been used in the library for converting 288 | between half-precision and single-precision values. 289 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | _doxygen/ 3 | sphinx/_toc.yml 4 | doxygen/html/ 5 | doxygen/xml/ 6 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | import re 8 | 9 | 10 | html_theme = "rocm_docs_theme" 11 | html_theme_options = {"flavor": "rocm"} 12 | 13 | extensions = ["rocm_docs", "rocm_docs.doxygen"] 14 | external_toc_path = "./sphinx/_toc.yml" 15 | doxygen_root = "doxygen" 16 | doxysphinx_enabled = True 17 | doxygen_project = { 18 | "name": "half", 19 | "path": "doxygen/xml", 20 | } 21 | 22 | with open('../CMakeLists.txt', encoding='utf-8') as f: 23 | match = re.search(r'rocm_setup_version\(VERSION\s+([0-9.]+)', f.read()) 24 | if not match: 25 | raise ValueError("VERSION not found!") 26 | version_number = match[1] 27 | 28 | version = version_number 29 | release = version_number 30 | html_title = f"half {version}" 31 | project = "half" 32 | author = "Advanced Micro Devices, Inc." 33 | copyright = ( 34 | "Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved." 35 | ) 36 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Home 3 | ======= 4 | 5 | .. include:: ../README.txt 6 | :literal: 7 | -------------------------------------------------------------------------------- /docs/license.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | License 3 | ======= 4 | 5 | .. include:: ../LICENSE.txt 6 | :literal: 7 | -------------------------------------------------------------------------------- /docs/sphinx/_toc.yml.in: -------------------------------------------------------------------------------- 1 | # Anywhere {branch} is used, the branch name will be substituted. 2 | # These comments will also be removed. 3 | defaults: 4 | numbered: False 5 | maxdepth: 6 6 | root: index 7 | subtrees: 8 | - caption: API Reference 9 | entries: 10 | - file: doxygen/html/index 11 | - caption: About 12 | entries: 13 | - file: license 14 | -------------------------------------------------------------------------------- /docs/sphinx/requirements.in: -------------------------------------------------------------------------------- 1 | rocm-docs-core[api_reference]==1.1.1 2 | -------------------------------------------------------------------------------- /docs/sphinx/requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.10 3 | # by the following command: 4 | # 5 | # pip-compile requirements.in 6 | # 7 | accessible-pygments==0.0.4 8 | # via pydata-sphinx-theme 9 | alabaster==0.7.16 10 | # via sphinx 11 | babel==2.14.0 12 | # via 13 | # pydata-sphinx-theme 14 | # sphinx 15 | beautifulsoup4==4.12.3 16 | # via pydata-sphinx-theme 17 | breathe==4.35.0 18 | # via rocm-docs-core 19 | certifi==2024.2.2 20 | # via requests 21 | cffi==1.16.0 22 | # via 23 | # cryptography 24 | # pynacl 25 | charset-normalizer==3.3.2 26 | # via requests 27 | click==8.1.7 28 | # via 29 | # click-log 30 | # doxysphinx 31 | # sphinx-external-toc 32 | click-log==0.4.0 33 | # via doxysphinx 34 | cryptography==42.0.5 35 | # via pyjwt 36 | deprecated==1.2.14 37 | # via pygithub 38 | docutils==0.21.2 39 | # via 40 | # breathe 41 | # myst-parser 42 | # pydata-sphinx-theme 43 | # sphinx 44 | doxysphinx==3.3.8 45 | # via rocm-docs-core 46 | fastjsonschema==2.19.1 47 | # via rocm-docs-core 48 | gitdb==4.0.11 49 | # via gitpython 50 | gitpython==3.1.43 51 | # via rocm-docs-core 52 | idna==3.7 53 | # via requests 54 | imagesize==1.4.1 55 | # via sphinx 56 | jinja2==3.1.3 57 | # via 58 | # myst-parser 59 | # sphinx 60 | libsass==0.22.0 61 | # via doxysphinx 62 | lxml==4.9.4 63 | # via doxysphinx 64 | markdown-it-py==3.0.0 65 | # via 66 | # mdit-py-plugins 67 | # myst-parser 68 | markupsafe==2.1.5 69 | # via jinja2 70 | mdit-py-plugins==0.4.0 71 | # via myst-parser 72 | mdurl==0.1.2 73 | # via markdown-it-py 74 | mpire==2.10.1 75 | # via doxysphinx 76 | myst-parser==3.0.1 77 | # via rocm-docs-core 78 | numpy==1.26.4 79 | # via doxysphinx 80 | packaging==24.0 81 | # via 82 | # pydata-sphinx-theme 83 | # sphinx 84 | pycparser==2.22 85 | # via cffi 86 | pydata-sphinx-theme==0.15.2 87 | # via 88 | # rocm-docs-core 89 | # sphinx-book-theme 90 | pygithub==2.3.0 91 | # via rocm-docs-core 92 | pygments==2.17.2 93 | # via 94 | # accessible-pygments 95 | # mpire 96 | # pydata-sphinx-theme 97 | # sphinx 98 | pyjson5==1.6.6 99 | # via doxysphinx 100 | pyjwt[crypto]==2.8.0 101 | # via pygithub 102 | pynacl==1.5.0 103 | # via pygithub 104 | pyparsing==3.1.2 105 | # via doxysphinx 106 | pyyaml==6.0.1 107 | # via 108 | # myst-parser 109 | # rocm-docs-core 110 | # sphinx-external-toc 111 | requests==2.31.0 112 | # via 113 | # pygithub 114 | # sphinx 115 | rocm-docs-core[api_reference]==1.1.1 116 | # via -r requirements.in 117 | smmap==5.0.1 118 | # via gitdb 119 | snowballstemmer==2.2.0 120 | # via sphinx 121 | soupsieve==2.5 122 | # via beautifulsoup4 123 | sphinx==7.3.7 124 | # via 125 | # breathe 126 | # myst-parser 127 | # pydata-sphinx-theme 128 | # rocm-docs-core 129 | # sphinx-book-theme 130 | # sphinx-copybutton 131 | # sphinx-design 132 | # sphinx-external-toc 133 | # sphinx-notfound-page 134 | sphinx-book-theme==1.1.2 135 | # via rocm-docs-core 136 | sphinx-copybutton==0.5.2 137 | # via rocm-docs-core 138 | sphinx-design==0.5.0 139 | # via rocm-docs-core 140 | sphinx-external-toc==1.0.1 141 | # via rocm-docs-core 142 | sphinx-notfound-page==1.0.0 143 | # via rocm-docs-core 144 | sphinxcontrib-applehelp==1.0.8 145 | # via sphinx 146 | sphinxcontrib-devhelp==1.0.6 147 | # via sphinx 148 | sphinxcontrib-htmlhelp==2.0.5 149 | # via sphinx 150 | sphinxcontrib-jsmath==1.0.1 151 | # via sphinx 152 | sphinxcontrib-qthelp==1.0.7 153 | # via sphinx 154 | sphinxcontrib-serializinghtml==1.1.10 155 | # via sphinx 156 | tomli==2.0.1 157 | # via sphinx 158 | tqdm==4.66.2 159 | # via mpire 160 | typing-extensions==4.11.0 161 | # via 162 | # pydata-sphinx-theme 163 | # pygithub 164 | urllib3==2.2.1 165 | # via 166 | # pygithub 167 | # requests 168 | wrapt==1.16.0 169 | # via deprecated 170 | -------------------------------------------------------------------------------- /half.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "half", "half.vcxproj", "{56F458B6-C7BA-49EE-981C-9766A2FAEB7C}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "web", "web\web.vcxproj", "{B36DE2E9-6E9C-4629-AEDA-8EFAE78E29D0}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\projects\vs2015\test.vcxproj", "{3949106C-CB15-4DD5-A1E6-13D5F067EC8C}" 11 | ProjectSection(ProjectDependencies) = postProject 12 | {56F458B6-C7BA-49EE-981C-9766A2FAEB7C} = {56F458B6-C7BA-49EE-981C-9766A2FAEB7C} 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Win32 = Debug|Win32 18 | Release|Win32 = Release|Win32 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {56F458B6-C7BA-49EE-981C-9766A2FAEB7C}.Debug|Win32.ActiveCfg = Debug|Win32 22 | {56F458B6-C7BA-49EE-981C-9766A2FAEB7C}.Debug|Win32.Build.0 = Debug|Win32 23 | {56F458B6-C7BA-49EE-981C-9766A2FAEB7C}.Release|Win32.ActiveCfg = Release|Win32 24 | {56F458B6-C7BA-49EE-981C-9766A2FAEB7C}.Release|Win32.Build.0 = Release|Win32 25 | {B36DE2E9-6E9C-4629-AEDA-8EFAE78E29D0}.Debug|Win32.ActiveCfg = Debug|Win32 26 | {B36DE2E9-6E9C-4629-AEDA-8EFAE78E29D0}.Debug|Win32.Build.0 = Debug|Win32 27 | {B36DE2E9-6E9C-4629-AEDA-8EFAE78E29D0}.Release|Win32.ActiveCfg = Release|Win32 28 | {B36DE2E9-6E9C-4629-AEDA-8EFAE78E29D0}.Release|Win32.Build.0 = Release|Win32 29 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Debug|Win32.ActiveCfg = Debug|Win32 30 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Debug|Win32.Build.0 = Debug|Win32 31 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Release|Win32.ActiveCfg = Release|Win32 32 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Release|Win32.Build.0 = Release|Win32 33 | EndGlobalSection 34 | GlobalSection(SolutionProperties) = preSolution 35 | HideSolutionNode = FALSE 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /half.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {56F458B6-C7BA-49EE-981C-9766A2FAEB7C} 15 | Win32Proj 16 | half 17 | 18 | 19 | 20 | Utility 21 | true 22 | Unicode 23 | v140 24 | 25 | 26 | Utility 27 | false 28 | true 29 | Unicode 30 | v140 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | $(ProjectName)d 45 | 46 | 47 | false 48 | 49 | 50 | 51 | 52 | 53 | Level3 54 | Disabled 55 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 56 | 57 | 58 | Console 59 | true 60 | 61 | 62 | 63 | 64 | Level3 65 | 66 | 67 | MaxSpeed 68 | true 69 | true 70 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 71 | 72 | 73 | Console 74 | true 75 | true 76 | true 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Document 85 | "C:\Program Files\doxygen\bin\doxygen.exe" $(InputPath) 86 | "C:\Program Files\doxygen\bin\doxygen.exe" $(InputPath) 87 | Generating Documentation 88 | Generating Documentation 89 | doc 90 | doc 91 | $(ProjectDir)include/half.hpp 92 | $(ProjectDir)include/half.hpp 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /half.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 6 | h;hpp;hxx;hm;inl;inc;xsd 7 | 8 | 9 | 10 | 11 | Headerdateien 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | CC = /usr/bin/g++ 2 | CFLAGS = -Wall -pedantic -g -O2 3 | C11FLAGS = -std=c++0x $(CFLAGS) 4 | CPPFLAGS = -I../include 5 | LDFLAGS = 6 | 7 | test11: src/test11.cpp ../include/half.hpp 8 | mkdir -p bin 9 | $(CC) $(C11FLAGS) $(CPPFLAGS) $(LDFLAGS) -o bin/test src/test11.cpp 10 | 11 | test03: src/test03.cpp ../include/half.hpp 12 | mkdir -p bin 13 | $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o bin/test src/test03.cpp 14 | 15 | asm11: src/test11.cpp ../include/half.hpp 16 | mkdir -p asm 17 | $(CC) $(C11FLAGS) $(CPPFLAGS) $(LDFLAGS) -S -o asm/test11.asm src/test11.cpp 18 | 19 | asm03: src/test11.cpp ../include/half.hpp 20 | mkdir -p asm 21 | $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -S -o asm/test03.asm src/test03.cpp 22 | 23 | clean: 24 | rm -rvf *~ src/*~ asm bin 25 | -------------------------------------------------------------------------------- /test/projects/vs2005/test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual C++ Express 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{DDAD59C9-019D-497B-9F64-8E8685DCB5AE}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {DDAD59C9-019D-497B-9F64-8E8685DCB5AE}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {DDAD59C9-019D-497B-9F64-8E8685DCB5AE}.Debug|Win32.Build.0 = Debug|Win32 14 | {DDAD59C9-019D-497B-9F64-8E8685DCB5AE}.Release|Win32.ActiveCfg = Release|Win32 15 | {DDAD59C9-019D-497B-9F64-8E8685DCB5AE}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /test/projects/vs2005/test.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 53 | 56 | 59 | 62 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 92 | 100 | 103 | 106 | 109 | 112 | 115 | 127 | 130 | 133 | 136 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 166 | 167 | 168 | 169 | 170 | 171 | 176 | 179 | 180 | 181 | 186 | 187 | 192 | 193 | 194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /test/projects/vs2008/test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual C++ Express 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{DDAD59C9-019D-497B-9F64-8E8685DCB5AE}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {DDAD59C9-019D-497B-9F64-8E8685DCB5AE}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {DDAD59C9-019D-497B-9F64-8E8685DCB5AE}.Debug|Win32.Build.0 = Debug|Win32 14 | {DDAD59C9-019D-497B-9F64-8E8685DCB5AE}.Release|Win32.ActiveCfg = Release|Win32 15 | {DDAD59C9-019D-497B-9F64-8E8685DCB5AE}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /test/projects/vs2008/test.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 53 | 56 | 59 | 62 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 92 | 100 | 103 | 106 | 109 | 112 | 115 | 127 | 130 | 133 | 136 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 166 | 167 | 168 | 169 | 170 | 171 | 176 | 179 | 180 | 181 | 186 | 187 | 192 | 193 | 194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /test/projects/vs2010/test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{3949106C-CB15-4DD5-A1E6-13D5F067EC8C}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Debug|Win32.Build.0 = Debug|Win32 14 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Release|Win32.ActiveCfg = Release|Win32 15 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /test/projects/vs2010/test.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | AssemblyAndSourceCode 16 | 17 | 18 | 19 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C} 20 | Win32Proj 21 | test 22 | 23 | 24 | 25 | Application 26 | true 27 | Unicode 28 | 29 | 30 | Application 31 | false 32 | true 33 | Unicode 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | true 47 | $(ProjectDir)..\..\bin\ 48 | $(ProjectDir)$(Configuration)\ 49 | $(ProjectName)d 50 | 51 | 52 | false 53 | $(ProjectDir)..\..\bin\ 54 | $(ProjectDir)$(Configuration)\ 55 | 56 | 57 | 58 | 59 | 60 | Level4 61 | Disabled 62 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 63 | $(ProjectDir)..\..\..\include\ 64 | 65 | 66 | Console 67 | true 68 | 69 | 70 | 71 | 72 | Level4 73 | 74 | 75 | MaxSpeed 76 | true 77 | true 78 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 79 | $(ProjectDir)..\..\..\include\ 80 | 81 | 82 | Console 83 | true 84 | true 85 | true 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /test/projects/vs2010/test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Quelldateien 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/projects/vs2012/test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{3949106C-CB15-4DD5-A1E6-13D5F067EC8C}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Debug|Win32.Build.0 = Debug|Win32 14 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Release|Win32.ActiveCfg = Release|Win32 15 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /test/projects/vs2012/test.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | AssemblyCode 16 | 17 | 18 | 19 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C} 20 | Win32Proj 21 | test 22 | 23 | 24 | 25 | Application 26 | true 27 | Unicode 28 | v110 29 | 30 | 31 | Application 32 | false 33 | true 34 | Unicode 35 | v110 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | true 49 | $(ProjectDir)..\..\bin\ 50 | $(ProjectDir)$(Configuration)\ 51 | $(ProjectName)d 52 | 53 | 54 | false 55 | $(ProjectDir)..\..\bin\ 56 | $(ProjectDir)$(Configuration)\ 57 | 58 | 59 | 60 | 61 | 62 | Level4 63 | Disabled 64 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 65 | $(ProjectDir)..\..\..\include\ 66 | 4127;4514;4668;4710;4711 67 | 68 | 69 | Console 70 | true 71 | 72 | 73 | 74 | 75 | 76 | 77 | MaxSpeed 78 | true 79 | true 80 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 81 | $(ProjectDir)..\..\..\include\ 82 | Level4 83 | 84 | 85 | Console 86 | true 87 | true 88 | true 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /test/projects/vs2012/test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Quelldateien 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/projects/vs2013/test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{3949106C-CB15-4DD5-A1E6-13D5F067EC8C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Debug|Win32.Build.0 = Debug|Win32 16 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Release|Win32.ActiveCfg = Release|Win32 17 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /test/projects/vs2013/test.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | AssemblyCode 16 | 17 | 18 | 19 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C} 20 | Win32Proj 21 | test 22 | 23 | 24 | 25 | Application 26 | true 27 | Unicode 28 | v120 29 | 30 | 31 | Application 32 | false 33 | true 34 | Unicode 35 | v120 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | true 49 | $(ProjectDir)..\..\bin\ 50 | $(ProjectDir)$(Configuration)\ 51 | $(ProjectName)d 52 | 53 | 54 | false 55 | $(ProjectDir)..\..\bin\ 56 | $(ProjectDir)$(Configuration)\ 57 | 58 | 59 | 60 | 61 | 62 | Level4 63 | Disabled 64 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 65 | $(ProjectDir)..\..\..\include\ 66 | 4127;4514;4668;4710;4711 67 | 68 | 69 | Console 70 | true 71 | 72 | 73 | 74 | 75 | 76 | 77 | MaxSpeed 78 | true 79 | true 80 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 81 | $(ProjectDir)..\..\..\include\ 82 | Level4 83 | 84 | 85 | Console 86 | true 87 | true 88 | true 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /test/projects/vs2013/test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Quelldateien 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/projects/vs2015/test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{3949106C-CB15-4DD5-A1E6-13D5F067EC8C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Debug|Win32.Build.0 = Debug|Win32 16 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Release|Win32.ActiveCfg = Release|Win32 17 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /test/projects/vs2015/test.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | AssemblyCode 16 | 17 | 18 | 19 | {3949106C-CB15-4DD5-A1E6-13D5F067EC8C} 20 | Win32Proj 21 | test 22 | 23 | 24 | 25 | Application 26 | true 27 | Unicode 28 | v140 29 | 30 | 31 | Application 32 | false 33 | true 34 | Unicode 35 | v140 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | true 49 | $(ProjectDir)..\..\bin\ 50 | $(ProjectDir)$(Configuration)\ 51 | $(ProjectName)d 52 | 53 | 54 | false 55 | $(ProjectDir)..\..\bin\ 56 | $(ProjectDir)$(Configuration)\ 57 | 58 | 59 | 60 | 61 | 62 | Level4 63 | Disabled 64 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 65 | $(ProjectDir)..\..\..\include\ 66 | 4127;4514;4668;4710;4711 67 | 68 | 69 | Console 70 | true 71 | 72 | 73 | 74 | 75 | 76 | 77 | MaxSpeed 78 | true 79 | true 80 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 81 | $(ProjectDir)..\..\..\include\ 82 | Level4 83 | 84 | 85 | Console 86 | true 87 | true 88 | true 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /test/projects/vs2015/test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Quelldateien 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/src/test03.cpp: -------------------------------------------------------------------------------- 1 | // test - Test application for half-precision floating point functionality. 2 | // 3 | // Copyright (c) 2012-2013 Christian Rau 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 6 | // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 7 | // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 13 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 15 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | 17 | #include 18 | 19 | using half_float::half; 20 | 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | half a(3.14159), b(-7), c = sin(a+b); 25 | std::cout << c << ", " << ilogb(c) << '\n'; 26 | } 27 | -------------------------------------------------------------------------------- /test/src/test11.cpp: -------------------------------------------------------------------------------- 1 | // test - Test application for half-precision floating point functionality. 2 | // 3 | // Copyright (c) 2012-2017 Christian Rau 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 6 | // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 7 | // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 13 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 15 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | 17 | #define HALF_ROUND_STYLE 1 18 | #define HALF_ROUND_TIES_TO_EVEN 1 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #if HALF_ENABLE_CPP11_HASH 39 | #include 40 | #endif 41 | 42 | 43 | #define UNARY_MATH_TEST(func) { \ 44 | double err = 0.0, rel = 0.0; \ 45 | bool success = unary_test(#func, [&](half arg) -> bool { \ 46 | half a = func(arg), b(std::func(static_cast(arg))); bool equal = comp(a, b); \ 47 | if(!equal) { double error = std::abs(static_cast(a)-static_cast(b)); \ 48 | err = std::max(err, error); rel = std::max(rel, error/std::abs(static_cast(arg))); } return equal; }); \ 49 | if(err != 0.0 || rel != 0.0) std::cout << #func << " max error: " << err << " - max relative error: " << rel << '\n'; } 50 | 51 | #define BINARY_MATH_TEST(func) { \ 52 | double err = 0.0, rel = 0.0; \ 53 | bool success = binary_test(#func, [&](half x, half y) -> bool { \ 54 | half a = func(x, y), b(std::func(static_cast(x), static_cast(y))); bool equal = comp(a, b); \ 55 | if(!equal) { double error = std::abs(static_cast(a)-static_cast(b)); \ 56 | err = std::max(err, error); rel = std::max(rel, error/std::min(std::abs(static_cast(x)), std::abs(static_cast(y)))); } return equal; }); \ 57 | if(err != 0.0 || rel != 0.0) std::cout << #func << " max error: " << err << " - max relative error: " << rel << '\n'; } 58 | 59 | 60 | using half_float::half; 61 | using half_float::half_cast; 62 | 63 | half b2h(std::uint16_t bits) 64 | { 65 | return *reinterpret_cast(&bits); 66 | } 67 | 68 | std::uint16_t h2b(half h) 69 | { 70 | return *reinterpret_cast(&h); 71 | } 72 | 73 | bool comp(half a, half b) 74 | { 75 | return (isnan(a) && isnan(b)) || a == b; 76 | } 77 | 78 | 79 | class half_test 80 | { 81 | public: 82 | half_test(std::ostream &log, bool fast) 83 | : tests_(0), log_(log), fast_(fast) 84 | { 85 | //prepare halfs 86 | half_vector batch; 87 | std::uint16_t u = 0; 88 | halfs_.insert(std::make_pair("positive zero", half_vector(1, b2h(u++)))); 89 | for(; u<0x400; ++u) 90 | batch.push_back(b2h(u)); 91 | halfs_.insert(std::make_pair("positive subn", std::move(batch))); 92 | batch.clear(); 93 | for(; u<0x7C00; ++u) 94 | batch.push_back(b2h(u)); 95 | halfs_.insert(std::make_pair("positive norm", std::move(batch))); 96 | batch.clear(); 97 | halfs_.insert(std::make_pair("positive inft", half_vector(1, b2h(u++)))); 98 | for(; u<0x8000; ++u) 99 | batch.push_back(b2h(u)); 100 | halfs_.insert(std::make_pair("positive NaN", std::move(batch))); 101 | batch.clear(); 102 | halfs_.insert(std::make_pair("negative zero", half_vector(1, b2h(u++)))); 103 | for(; u<0x8400; ++u) 104 | batch.push_back(b2h(u)); 105 | halfs_.insert(std::make_pair("negative subn", std::move(batch))); 106 | batch.clear(); 107 | for(; u<0xFC00; ++u) 108 | batch.push_back(b2h(u)); 109 | halfs_.insert(std::make_pair("negative norm", std::move(batch))); 110 | batch.clear(); 111 | halfs_.insert(std::make_pair("negative inft", half_vector(1, b2h(u++)))); 112 | for(; u!=0; ++u) 113 | batch.push_back(b2h(u)); 114 | halfs_.insert(std::make_pair("negative NaN", std::move(batch))); 115 | 116 | //set classes 117 | classes_["positive zero"] = FP_ZERO; 118 | classes_["positive subn"] = FP_SUBNORMAL; 119 | classes_["positive norm"] = FP_NORMAL; 120 | classes_["positive inft"] = FP_INFINITE; 121 | classes_["positive NaN"] = FP_NAN; 122 | classes_["negative zero"] = FP_ZERO; 123 | classes_["negative subn"] = FP_SUBNORMAL; 124 | classes_["negative norm"] = FP_NORMAL; 125 | classes_["negative inft"] = FP_INFINITE; 126 | classes_["negative NaN"] = FP_NAN; 127 | } 128 | 129 | unsigned int test() 130 | { 131 | //test size 132 | simple_test("size", []() { return sizeof(half)*CHAR_BIT >= 16; }); 133 | 134 | //test conversion 135 | unary_test("float conversion", [](half arg) { return comp(half_cast(half_cast(arg)), arg); }); 136 | unary_test("double conversion", [](half arg) { return comp(half_cast(half_cast(arg)), arg); }); 137 | unary_test("long double conversion", [](half arg) { return comp(half_cast(half_cast(arg)), arg); }); 138 | 139 | //test classification 140 | class_test("fpclassify", [](half arg, int cls) { return fpclassify(arg) == cls; }); 141 | class_test("isfinite", [](half arg, int cls) { return isfinite(arg) == (cls!=FP_INFINITE&&cls!=FP_NAN); }); 142 | class_test("isinf", [](half arg, int cls) { return isinf(arg) == (cls==FP_INFINITE); }); 143 | class_test("isnan", [](half arg, int cls) { return isnan(arg) == (cls==FP_NAN); }); 144 | class_test("isnormal", [](half arg, int cls) { return isnormal(arg) == (cls==FP_NORMAL); }); 145 | unary_test("signbit", [](half arg) -> bool { double f = arg; return isnan(arg) || f==0.0 || (signbit(arg)==(f<0.0)); }); 146 | 147 | //test operators 148 | unary_test("prefix increment", [](half arg) -> bool { double f = static_cast(arg); 149 | return comp(static_cast(++f), ++arg) && comp(static_cast(f), arg); }); 150 | unary_test("prefix decrement", [](half arg) -> bool { double f = static_cast(arg); 151 | return comp(static_cast(--f), --arg) && comp(static_cast(f), arg); }); 152 | unary_test("postfix increment", [](half arg) -> bool { double f = static_cast(arg); 153 | return comp(static_cast(f++), arg++) && comp(static_cast(f), arg); }); 154 | unary_test("postfix decrement", [](half arg) -> bool { double f = static_cast(arg); 155 | return comp(static_cast(f--), arg--) && comp(static_cast(f), arg); }); 156 | unary_test("unary plus", [](half arg) { return comp(+arg, arg); }); 157 | unary_test("unary minus", [](half arg) { return comp(-arg, static_cast(-static_cast(arg))); }); 158 | binary_test("addition", [](half a, half b) { return comp(a+b, static_cast(static_cast(a)+static_cast(b))); }); 159 | binary_test("subtraction", [](half a, half b) { return comp(a-b, static_cast(static_cast(a)-static_cast(b))); }); 160 | binary_test("multiplication", [](half a, half b) { return comp(a*b, static_cast(static_cast(a)*static_cast(b))); }); 161 | binary_test("division", [](half a, half b) { return comp(a/b, static_cast(static_cast(a)/static_cast(b))); }); 162 | binary_test("equal", [](half a, half b) { return (a==b) == (static_cast(a)==static_cast(b)); }); 163 | binary_test("not equal", [](half a, half b) { return (a!=b) == (static_cast(a)!=static_cast(b)); }); 164 | binary_test("less", [](half a, half b) { return (a(a)(b)); }); 165 | binary_test("greater", [](half a, half b) { return (a>b) == (static_cast(a)>static_cast(b)); }); 166 | binary_test("less equal", [](half a, half b) { return (a<=b) == (static_cast(a)<=static_cast(b)); }); 167 | binary_test("greater equal", [](half a, half b) { return (a>=b) == (static_cast(a)>=static_cast(b)); }); 168 | 169 | //test basic functions 170 | UNARY_MATH_TEST(abs); 171 | UNARY_MATH_TEST(fabs); 172 | BINARY_MATH_TEST(fmod); 173 | binary_test("fdim", [](half a, half b) -> bool { half c = fdim(a, b); return isnan(a) || isnan(b) || 174 | (isinf(a) && isinf(b) && signbit(a)==signbit(b)) || ((a>b) && comp(c, a-b)) || ((a<=b) && comp(c, static_cast(0.0f))); }); 175 | 176 | //test exponential functions 177 | UNARY_MATH_TEST(exp); 178 | UNARY_MATH_TEST(log); 179 | UNARY_MATH_TEST(log10); 180 | 181 | //test power functions 182 | UNARY_MATH_TEST(sqrt); 183 | BINARY_MATH_TEST(pow); 184 | 185 | //test trig functions 186 | UNARY_MATH_TEST(sin); 187 | UNARY_MATH_TEST(cos); 188 | UNARY_MATH_TEST(tan); 189 | UNARY_MATH_TEST(asin); 190 | UNARY_MATH_TEST(acos); 191 | UNARY_MATH_TEST(atan); 192 | BINARY_MATH_TEST(atan2); 193 | 194 | //test hyp functions 195 | UNARY_MATH_TEST(sinh); 196 | UNARY_MATH_TEST(cosh); 197 | UNARY_MATH_TEST(tanh); 198 | 199 | //test round functions 200 | UNARY_MATH_TEST(ceil); 201 | UNARY_MATH_TEST(floor); 202 | unary_test("trunc", [](half arg) { return !isfinite(arg) || comp(trunc(arg), static_cast(static_cast(arg))); }); 203 | unary_test("round", [](half arg) { return !isfinite(arg) || comp(round(arg), 204 | static_cast(static_cast(static_cast(arg)+(signbit(arg) ? -0.5 : 0.5)))); }); 205 | unary_test("lround", [](half arg) { return !isfinite(arg) || lround(arg) == 206 | static_cast(static_cast(arg)+(signbit(arg) ? -0.5 : 0.5)); }); 207 | unary_test("nearbyint", [](half arg) { return !isfinite(arg) || comp(nearbyint(arg), static_cast(half_cast(arg))); }); 208 | unary_test("rint", [](half arg) { return !isfinite(arg) || comp(rint(arg), static_cast(half_cast(arg))); }); 209 | unary_test("lrint", [](half arg) { return !isfinite(arg) || lrint(arg) == half_cast(arg); }); 210 | #if HALF_ENABLE_CPP11_LONG_LONG 211 | unary_test("llround", [](half arg) { return !isfinite(arg) || llround(arg) == 212 | static_cast(static_cast(arg)+(signbit(arg) ? -0.5 : 0.5)); }); 213 | unary_test("llrint", [](half arg) { return !isfinite(arg) || llrint(arg) == half_cast(arg); }); 214 | #endif 215 | 216 | //test float functions 217 | unary_test("frexp", [](half arg) -> bool { int eh, ef; bool eq = comp(frexp(arg, &eh), 218 | static_cast(std::frexp(static_cast(arg), &ef))); return eq && (!isfinite(arg) || eh==ef); }); 219 | unary_test("ldexp", [](half arg) -> bool { unsigned int passed = 0; for(int i=-50; i<50; ++i) passed += 220 | comp(ldexp(arg, i), static_cast(std::ldexp(static_cast(arg), i))); return passed==100; }); 221 | unary_test("modf", [](half arg) -> bool { half h; double f; return comp(modf(arg, &h), static_cast( 222 | std::modf(static_cast(arg), &f))) && comp(h, static_cast(f)); }); 223 | binary_test("nextafter", [](half a, half b) -> bool { half c = nextafter(a, b); std::int16_t d = std::abs( 224 | static_cast(h2b(a)-h2b(c))); return ((isnan(a) || isnan(b)) && isnan(c)) || 225 | (comp(a, b) && comp(b, c)) || ((d==1||d==0x7FFF) && (a bool { half c = nexttoward(a, static_cast(b)); std::int16_t d = std::abs( 227 | static_cast(h2b(a)-h2b(c))); return ((isnan(a) || isnan(b)) && isnan(c)) || 228 | (comp(a, b) && comp(b, c)) || ((d==1||d==0x7FFF) && (a bool { half h = copysign(a, b); 230 | return comp(abs(h), abs(a)) && signbit(h)==signbit(b); }); 231 | 232 | #if HALF_ENABLE_CPP11_CMATH 233 | //test basic functions 234 | BINARY_MATH_TEST(remainder); 235 | binary_test("remquo", [](half a, half b) -> bool { int qh = 0, qf = 0; bool eq = comp(remquo(a, b, &qh), 236 | static_cast(std::remquo(static_cast(a), static_cast(b), &qf))); return eq && (qh&7)==(qf&7); }); 237 | BINARY_MATH_TEST(fmin); 238 | BINARY_MATH_TEST(fmax); 239 | BINARY_MATH_TEST(fdim); 240 | 241 | //test exponential functions 242 | UNARY_MATH_TEST(exp2); 243 | UNARY_MATH_TEST(expm1); 244 | UNARY_MATH_TEST(log1p); 245 | UNARY_MATH_TEST(log2); 246 | 247 | //test power functions 248 | UNARY_MATH_TEST(cbrt); 249 | BINARY_MATH_TEST(hypot); 250 | 251 | //test hyp functions 252 | UNARY_MATH_TEST(asinh); 253 | UNARY_MATH_TEST(acosh); 254 | UNARY_MATH_TEST(atanh); 255 | 256 | //test err functions 257 | UNARY_MATH_TEST(erf); 258 | UNARY_MATH_TEST(erfc); 259 | UNARY_MATH_TEST(lgamma); 260 | UNARY_MATH_TEST(tgamma); 261 | 262 | //test round functions 263 | UNARY_MATH_TEST(trunc); 264 | UNARY_MATH_TEST(round); 265 | unary_test("lround", [](half arg) { return !isfinite(arg) || lround(arg) == std::lround(static_cast(arg)); }); 266 | unary_test("llround", [](half arg) { return !isfinite(arg) || llround(arg) == std::llround(static_cast(arg)); }); 267 | #if HALF_ROUND_STYLE == 1 && HALF_ROUND_TIES_TO_EVEN == 1 268 | UNARY_MATH_TEST(nearbyint); 269 | UNARY_MATH_TEST(rint); 270 | unary_test("lrint", [](half arg) { return !isfinite(arg) || half_float::lrint(arg) == std::lrint(static_cast(arg)); }); 271 | unary_test("llrint", [](half arg) { return !isfinite(arg) || llrint(arg) == std::llrint(static_cast(arg)); }); 272 | #endif 273 | 274 | //test float functions 275 | unary_test("scalbn", [](half arg) -> bool { unsigned int passed = 0; for(int i=-50; i<50; ++i) passed += 276 | comp(scalbn(arg, i), static_cast(std::scalbn(static_cast(arg), i))); return passed==100; }); 277 | unary_test("scalbln", [](half arg) -> bool { unsigned int passed = 0; for(long i=-50; i<50; ++i) passed += 278 | comp(scalbln(arg, i), static_cast(std::scalbln(static_cast(arg), i))); return passed==100; }); 279 | unary_test("ilogb", [](half arg) { return ilogb(arg) == std::ilogb(static_cast(arg)); }); 280 | unary_test("logb", [](half arg) { return comp(logb(arg), static_cast(std::logb(static_cast(arg)))); }); 281 | binary_test("copysign", [](half a, half b) { return comp(copysign(a, b), 282 | static_cast(std::copysign(static_cast(a), static_cast(b)))); }); 283 | 284 | //test classification functions 285 | unary_test("fpclassify", [](half arg) -> bool { int ch=fpclassify(arg), cf=std::fpclassify( 286 | static_cast(arg)); return ch==cf || (ch==FP_SUBNORMAL && cf==FP_NORMAL); }); 287 | unary_test("isfinite", [](half arg) { return isfinite(arg) == std::isfinite(static_cast(arg)); }); 288 | unary_test("isinf", [](half arg) { return isinf(arg) == std::isinf(static_cast(arg)); }); 289 | unary_test("isnan", [](half arg) { return isnan(arg) == std::isnan(static_cast(arg)); }); 290 | unary_test("isnormal", [](half arg) { return isnormal(arg) == std::isnormal(static_cast(arg)) || 291 | (!isnormal(arg) && fpclassify(arg)==FP_SUBNORMAL); }); 292 | unary_test("signbit", [](half arg) { return signbit(arg) == std::signbit(static_cast(arg)); }); 293 | 294 | //test comparison functions 295 | binary_test("isgreater", [](half a, half b) { return isgreater(a, b) == 296 | std::isgreater(static_cast(a), static_cast(b)); }); 297 | binary_test("isgreaterequal", [](half a, half b) { return isgreaterequal(a, b) == 298 | std::isgreaterequal(static_cast(a), static_cast(b)); }); 299 | binary_test("isless", [](half a, half b) { return isless(a, b) == 300 | std::isless(static_cast(a), static_cast(b)); }); 301 | binary_test("islessequal", [](half a, half b) { return islessequal(a, b) == 302 | std::islessequal(static_cast(a), static_cast(b)); }); 303 | binary_test("islessgreater", [](half a, half b) { return islessgreater(a, b) == 304 | std::islessgreater(static_cast(a), static_cast(b)); }); 305 | binary_test("isunordered", [](half a, half b) { return isunordered(a, b) == 306 | std::isunordered(static_cast(a), static_cast(b)); }); 307 | #endif 308 | 309 | //test rounding 310 | float_test("round_to_nearest", [](float f) -> bool { half a = half_cast(f), 311 | b(nextafter(a, copysign(std::numeric_limits::infinity(), a))), h = half_cast(f); 312 | float af(a), bf(b), hf(h); return half_float::detail::builtin_isnan(f) || 313 | (std::abs(hf)>std::abs(f)&&comp(h, b)&&(( 314 | #if HALF_ROUND_TIES_TO_EVEN 315 | std::abs(f-af)>std::abs(bf-f) || (std::abs(f-af)==std::abs(bf-f)&&!(h2b(h)&1)) 316 | #else 317 | std::abs(f-af)>=std::abs(bf-f) 318 | #endif 319 | )||isinf(h))) || (std::abs(hf)<=std::abs(f)&&comp(h, a)&&(( 320 | #if HALF_ROUND_TIES_TO_EVEN 321 | std::abs(f-af) bool { half a = half_cast(f), 327 | h = half_cast(f); float af(a), hf(h); return half_float::detail::builtin_isnan(f) || isinf(a) || af == hf; }); 328 | float_test("round_toward_infinity", [](float f) -> bool { half a = half_cast(f), 329 | b(nextafter(a, copysign(std::numeric_limits::infinity(), a))), h = half_cast(f); 330 | float hf(h); return half_float::detail::builtin_isnan(f) || (comp(h, a)&&(signbit(h)||hf==f)) || (comp(h, b)&&!signbit(h)&&hf>f); }); 331 | float_test("round_toward_neg_infinity", [](float f) -> bool { half a = half_cast(f), 332 | b(nextafter(a, copysign(std::numeric_limits::infinity(), a))), h = half_cast(f); 333 | float hf(h); return half_float::detail::builtin_isnan(f) || (comp(h, a)&&(!signbit(h)||hf==f)) || (comp(h, b)&&signbit(h)&&hf(0, (1<<23)-1), std::default_random_engine()); 337 | unary_test("half_cast", [](half arg) -> bool { float a = half_cast(arg), b = static_cast(arg); 338 | return *reinterpret_cast(&a) == *reinterpret_cast(&b); }); 339 | unary_test("half_cast(float)", [&rand23](half arg) -> bool { float f = half_cast(arg); 340 | std::uint32_t n=rand23(), m=1<<13; if(fpclassify(arg)==FP_SUBNORMAL) m <<= std::min(std::max(-ilogb(arg)-14, 0), 10); 341 | *reinterpret_cast(&f) |= n&(m-1)&-isfinite(arg); return fpclassify(arg)==FP_ZERO || 342 | comp(half_cast(f), 343 | #if HALF_ROUND_TIES_TO_EVEN 344 | ((n&(m>>1)) && ((n&((m>>1)-1)) || (h2b(arg)&1))) 345 | #else 346 | (n&(m>>1)) 347 | #endif 348 | ? nextafter(arg, copysign(std::numeric_limits::infinity(), arg)) : arg); }); 349 | unary_test("half_cast(float)", [&rand23](half arg) -> bool { float f = half_cast(arg); 350 | std::uint32_t n=rand23(), m=1<<13; if(fpclassify(arg)==FP_SUBNORMAL) m <<= std::min(std::max(-ilogb(arg)-14, 0), 10); 351 | *reinterpret_cast(&f) |= n&(m-1)&-isfinite(arg); return comp(half_cast(f), arg); }); 352 | unary_test("half_cast(float)", [&rand23](half arg) -> bool { float f = half_cast(arg); 353 | std::uint32_t n=rand23(), m=1<<13; if(fpclassify(arg)==FP_SUBNORMAL) m <<= std::min(std::max(-ilogb(arg)-14, 0), 10); 354 | *reinterpret_cast(&f) |= n&(m-1)&-isfinite(arg); return comp(half_cast(f), 355 | (!signbit(arg)&&(n&(m-1))) ? nextafter(arg, copysign(std::numeric_limits::infinity(), arg)) : arg); }); 356 | unary_test("half_cast(float)", [&rand23](half arg) -> bool { float f = half_cast(arg); 357 | std::uint32_t n=rand23(), m=1<<13; if(fpclassify(arg)==FP_SUBNORMAL) m <<= std::min(std::max(-ilogb(arg)-14, 0), 10); 358 | *reinterpret_cast(&f) |= n&(m-1)&-isfinite(arg); return comp(half_cast(f), 359 | (signbit(arg)&&(n&(m-1))) ? nextafter(arg, copysign(std::numeric_limits::infinity(), arg)) : arg); }); 360 | 361 | //test double casting 362 | auto rand52 = std::bind(std::uniform_int_distribution(0, (1ULL<<52)-1), std::default_random_engine()); 363 | unary_test("half_cast", [](half arg) -> bool { double a = half_cast(arg), b = static_cast(arg); 364 | return isnan(arg) || *reinterpret_cast(&a) == *reinterpret_cast(&b); }); 365 | unary_test("half_cast(double)", [&rand52](half arg) -> bool { double f = half_cast(arg); 366 | std::uint64_t n=rand52(), m=1ULL<<42; if(fpclassify(arg)==FP_SUBNORMAL) m <<= std::min(std::max(-ilogb(arg)-14, 0), 10); 367 | *reinterpret_cast(&f) |= n&(m-1)&-isfinite(arg); return fpclassify(arg)==FP_ZERO || 368 | comp(half_cast(f), 369 | #if HALF_ROUND_TIES_TO_EVEN 370 | ((n&(m>>1)) && ((n&((m>>1)-1)) || (h2b(arg)&1))) 371 | #else 372 | (n&(m>>1)) 373 | #endif 374 | ? nextafter(arg, copysign(std::numeric_limits::infinity(), arg)) : arg); }); 375 | unary_test("half_cast(double)", [&rand52](half arg) -> bool { double f = half_cast(arg); 376 | std::uint64_t n=rand52(), m=1ULL<<42; if(fpclassify(arg)==FP_SUBNORMAL) m <<= std::min(std::max(-ilogb(arg)-14, 0), 10); 377 | *reinterpret_cast(&f) |= n&(m-1)&-isfinite(arg); return comp(half_cast(f), arg); }); 378 | unary_test("half_cast(double)", [&rand52](half arg) -> bool { double f = half_cast(arg); 379 | std::uint64_t n=rand52(), m=1ULL<<42; if(fpclassify(arg)==FP_SUBNORMAL) m <<= std::min(std::max(-ilogb(arg)-14, 0), 10); 380 | *reinterpret_cast(&f) |= n&(m-1)&-isfinite(arg); return comp(half_cast(f), 381 | (!signbit(arg)&&(n&(m-1))) ? nextafter(arg, copysign(std::numeric_limits::infinity(), arg)) : arg); }); 382 | unary_test("half_cast(double)", [&rand52](half arg) -> bool { double f = half_cast(arg); 383 | std::uint64_t n=rand52(), m=1ULL<<42; if(fpclassify(arg)==FP_SUBNORMAL) m <<= std::min(std::max(-ilogb(arg)-14, 0), 10); 384 | *reinterpret_cast(&f) |= n&(m-1)&-isfinite(arg); return comp(half_cast(f), 385 | (signbit(arg)&&(n&(m-1))) ? nextafter(arg, copysign(std::numeric_limits::infinity(), arg)) : arg); }); 386 | 387 | //test casting to int 388 | #if HALF_ENABLE_CPP11_CMATH 389 | unary_test("half_cast", [](half arg) -> bool { return !isfinite(arg) || half_cast(arg) == static_cast(nearbyint(arg)); }); 390 | #endif 391 | unary_test("half_cast", [](half arg) -> bool { float fi, ff = std::abs(std::modf(static_cast(arg), &fi)); 392 | int i = static_cast(fi); i += (-2*signbit(arg)+1) * 393 | #if HALF_ROUND_TIES_TO_EVEN 394 | (ff>0.5f || (ff==0.5f && i&1)); 395 | #else 396 | (ff>=0.5f); 397 | #endif 398 | return !isfinite(arg) || half_cast(arg) == i; 399 | }); 400 | unary_test("half_cast", [](half arg) -> bool { return !isfinite(arg) || half_cast(arg) == static_cast(arg); }); 401 | unary_test("half_cast", [](half arg) -> bool { float fi, ff = std::modf(static_cast(arg), &fi); 402 | return !isfinite(arg) || half_cast(arg) == (static_cast(fi)+(ff>0.0f)); }); 403 | unary_test("half_cast", [](half arg) -> bool { float fi, ff = std::modf(static_cast(arg), &fi); 404 | return !isfinite(arg) || half_cast(arg) == (static_cast(fi)-(ff<0.0f)); }); 405 | 406 | //test casting from int 407 | int_test("half_cast<>(int)", [](int i) -> bool { return comp(half_cast(i), half_cast(static_cast(i))); }); 408 | int_test("half_cast(int)", [](int i) -> bool { 409 | return comp(half_cast(i), half_cast(static_cast(i))); }); 410 | int_test("half_cast(int)", [](int i) -> bool { 411 | return comp(half_cast(i), half_cast(static_cast(i))); }); 412 | int_test("half_cast(int)", [](int i) -> bool { 413 | return comp(half_cast(i), half_cast(static_cast(i))); }); 414 | int_test("half_cast(int)", [](int i) -> bool { 415 | return comp(half_cast(i), half_cast(static_cast(i))); }); 416 | 417 | //test numeric limits 418 | unary_test("numeric_limits::min", [](half arg) { return !isnormal(arg) || signbit(arg) || arg>=std::numeric_limits::min(); }); 419 | unary_test("numeric_limits::lowest", [](half arg) { return !isfinite(arg) || arg>=std::numeric_limits::lowest(); }); 420 | unary_test("numeric_limits::max", [](half arg) { return !isfinite(arg) || arg<=std::numeric_limits::max(); }); 421 | unary_test("numeric_limits::denorm_min", [](half arg) { return !isfinite(arg) || 422 | signbit(arg) || arg==static_cast(0.0f) || arg>=std::numeric_limits::denorm_min(); }); 423 | simple_test("numeric_limits::infinity", []() { return isinf(std::numeric_limits::infinity()) && 424 | !signbit(std::numeric_limits::infinity()); }); 425 | simple_test("numeric_limits::quiet_NaN", []() { return isnan(std::numeric_limits::quiet_NaN()); }); 426 | simple_test("numeric_limits::signaling_NaN", []() { return isnan(std::numeric_limits::signaling_NaN()); }); 427 | simple_test("numeric_limits::epsilon", []() { return nextafter(static_cast(1.0f), 428 | std::numeric_limits::infinity())-static_cast(1.0f) == std::numeric_limits::epsilon(); }); 429 | binary_test("numeric_limits::round_error", [](half a, half b) -> bool { double c = static_cast(a) + 430 | static_cast(b); return !isfinite(a) || !isfinite(b) || c>static_cast(std::numeric_limits::max()) || 431 | c(std::numeric_limits::lowest()) || std::abs(c-static_cast( 432 | static_cast(c)))<=std::ldexp(static_cast(std::numeric_limits::round_error()), 433 | ilogb(static_cast(c))-std::numeric_limits::digits+1); }); 434 | 435 | #if HALF_ENABLE_CPP11_HASH 436 | //test hash 437 | binary_test("hash function", [](half a, half b) { return a != b || std::hash()(a) == std::hash()(b); }); 438 | struct { bool operator()(half a, half b) const { return h2b(a) == h2b(b); } } bincomp; 439 | std::unordered_map,decltype(bincomp)> map(65536, std::hash(), bincomp); 440 | unary_test("hash insert", [&map](const half &arg) { return map.insert(std::make_pair(arg, &arg)).second; }); 441 | unary_test("hash retrieve", [&map](const half &arg) { return map[arg] == &arg; }); 442 | #endif 443 | 444 | #if HALF_ENABLE_CPP11_USER_LITERALS 445 | //test literals 446 | simple_test("literals", []() -> bool { using namespace half_float::literal; return comp(0.0_h, half(0.0f)) && comp(-1.0_h, half(-1.0f)) && 447 | comp(+3.14159265359_h, half(3.14159265359f)) && comp(1e-2_h, half(1e-2f)) && comp(-4.2e3_h, half(-4.2e3f)); }); 448 | #endif 449 | 450 | if(failed_.empty()) 451 | log_ << "all tests passed\n"; 452 | else 453 | { 454 | log_ << (failed_.size()) << " OF " << tests_ << " FAILED:\n "; 455 | std::copy(failed_.begin(), failed_.end(), std::ostream_iterator(log_, "\n ")); 456 | log_ << '\n'; 457 | } 458 | return failed_.size(); 459 | } 460 | 461 | private: 462 | typedef std::vector half_vector; 463 | typedef std::map test_map; 464 | typedef std::map class_map; 465 | 466 | template bool class_test(const std::string &name, F test) 467 | { 468 | unsigned int count = 0; 469 | log_ << "testing " << name << ":\n"; 470 | for(auto iterB=halfs_.begin(); iterB!=halfs_.end(); ++iterB) 471 | { 472 | unsigned int passed = 0; 473 | int fpclass = classes_[iterB->first]; 474 | for(auto iterH=iterB->second.begin(); iterH!=iterB->second.end(); ++iterH) 475 | passed += test(*iterH, fpclass); 476 | log_ << " " << iterB->first << ": "; 477 | if(passed == iterB->second.size()) 478 | { 479 | log_ << "all passed\n"; 480 | ++count; 481 | } 482 | else 483 | log_ << (iterB->second.size()-passed) << " of " << iterB->second.size() << " FAILED\n"; 484 | } 485 | log_ << '\n'; 486 | ++tests_; 487 | if(count == halfs_.size()) 488 | return true; 489 | failed_.push_back(name); 490 | return false; 491 | } 492 | 493 | template bool simple_test(const std::string &name, F test) 494 | { 495 | log_ << "testing " << name << ": "; 496 | bool passed = test(); 497 | log_ << (passed ? "passed" : "FAILED") << "\n\n"; 498 | ++tests_; 499 | if(!passed) 500 | failed_.push_back(name); 501 | return passed; 502 | } 503 | 504 | template bool unary_test(const std::string &name, F test) 505 | { 506 | unsigned int count = 0; 507 | log_ << "testing " << name << ":\n"; 508 | for(auto iterB=halfs_.begin(); iterB!=halfs_.end(); ++iterB) 509 | { 510 | unsigned int passed = 0; 511 | for(auto iterH=iterB->second.begin(); iterH!=iterB->second.end(); ++iterH) 512 | passed += test(*iterH); 513 | log_ << " " << iterB->first << ": "; 514 | if(passed == iterB->second.size()) 515 | { 516 | log_ << "all passed\n"; 517 | ++count; 518 | } 519 | else 520 | log_ << (iterB->second.size()-passed) << " of " << iterB->second.size() << " FAILED\n"; 521 | } 522 | log_ << '\n'; 523 | ++tests_; 524 | if(count == halfs_.size()) 525 | return true; 526 | failed_.push_back(name); 527 | return false; 528 | } 529 | 530 | template bool binary_test(const std::string &name, F test) 531 | { 532 | unsigned long tests = 0, count = 0, step = fast_ ? 64 : 1; 533 | auto rand = std::bind(std::uniform_int_distribution(0, step-1), std::default_random_engine()); 534 | log_ << "testing " << name << ": "; 535 | for(auto iterB1=halfs_.begin(); iterB1!=halfs_.end(); ++iterB1) 536 | { 537 | for(auto iterB2=halfs_.begin(); iterB2!=halfs_.end(); ++iterB2) 538 | { 539 | unsigned int end1 = (iterB1->first.find("NaN")==std::string::npos) ? iterB1->second.size() : 1; 540 | unsigned int end2 = (iterB2->first.find("NaN")==std::string::npos) ? iterB2->second.size() : 1; 541 | for(unsigned int i=fast_ ? std::min(rand(), iterB1->second.size()-1) : 0; isecond.size()-1) : 0; jsecond[i], iterB2->second[j]); 547 | } 548 | } 549 | } 550 | } 551 | bool passed = count == tests; 552 | if(passed) 553 | log_ << "all passed\n\n"; 554 | else 555 | { 556 | log_ << (tests-count) << " of " << tests << " FAILED\n\n"; 557 | failed_.push_back(name); 558 | } 559 | ++tests_; 560 | return passed; 561 | } 562 | 563 | template bool float_test(const std::string &name, F test) 564 | { 565 | auto rand32 = std::bind(std::uniform_int_distribution(0, std::numeric_limits::max()), std::default_random_engine()); 566 | unsigned long long count = 0, tests = fast_ ? 1e6 : (1ULL<<32); 567 | log_ << "testing " << name << ": "; 568 | if(fast_) 569 | { 570 | for(unsigned long long i=0; i(&u)); 574 | } 575 | } 576 | else 577 | for(std::uint32_t i=0; i++>0; ) 578 | count += test(*reinterpret_cast(&i)); 579 | bool passed = count == tests; 580 | if(passed) 581 | log_ << "all passed\n\n"; 582 | else 583 | { 584 | log_ << (tests-count) << " of " << tests << " FAILED\n\n"; 585 | failed_.push_back(name); 586 | } 587 | ++tests_; 588 | return passed; 589 | } 590 | 591 | template bool int_test(const std::string &name, F test) 592 | { 593 | unsigned int count = 0, tests = (1<<17) + 1; 594 | log_ << "testing " << name << ": "; 595 | for(int i=-(1<<16); i<=(1<<16); ++i) 596 | count += test(i); 597 | bool passed = count == tests; 598 | if(passed) 599 | log_ << "all passed\n\n"; 600 | else 601 | { 602 | log_ << (tests-count) << " of " << tests << " FAILED\n\n"; 603 | failed_.push_back(name); 604 | } 605 | ++tests_; 606 | return passed; 607 | } 608 | 609 | test_map halfs_; 610 | class_map classes_; 611 | unsigned int tests_; 612 | std::vector failed_; 613 | std::ostream &log_; 614 | bool fast_; 615 | }; 616 | 617 | #include 618 | struct timer 619 | { 620 | timer() : start_(std::chrono::high_resolution_clock::now()) {} 621 | ~timer() { std::cout << "time: " << std::chrono::duration_cast(std::chrono::high_resolution_clock::now()-start_).count() << " ms\n"; } 622 | 623 | private: 624 | std::chrono::time_point start_; 625 | }; 626 | 627 | int main(int argc, char *argv[]) 628 | { 629 | /* auto rand_abs = std::bind(std::uniform_int_distribution(0x00000000, 0x7F100000), std::default_random_engine()); 630 | auto rand_sign = std::bind(std::uniform_int_distribution(0, 1), std::default_random_engine()); 631 | std::vector floats; 632 | for(unsigned int i=0; i<1e8; ++i) 633 | { 634 | auto bits = rand_abs() | (rand_sign()<<31); 635 | floats.push_back(*reinterpret_cast(&bits)); 636 | } 637 | std::shuffle(floats.begin(), floats.end(), std::default_random_engine()); 638 | std::vector halfs(floats.size()); 639 | { 640 | timer time; 641 | for(std::size_t i=0; i(floats[i]); 643 | } 644 | return 0; 645 | */ 646 | half pi = half_cast(3.1415926535897932384626433832795L); 647 | std::cout << "Pi: " << pi << " - 0x" << std::hex << std::setfill('0') << std::setw(4) << h2b(pi) << std::dec 648 | << " - " << std::bitset<16>(static_cast(h2b(pi))).to_string() << std::endl; 649 | half e = half_cast(std::exp(1.0L)); 650 | std::cout << "e: " << e << " - 0x" << std::hex << std::setfill('0') << std::setw(4) << h2b(e) << std::dec 651 | << " - " << std::bitset<16>(static_cast(h2b(e))).to_string() << std::endl; 652 | 653 | std::vector args(argv, argv+argc); 654 | std::unique_ptr file; 655 | bool fast = false; 656 | for(auto iter=std::next(args.begin()); iter!=args.end(); ++iter) 657 | { 658 | if(*iter == "-fast") 659 | fast = true; 660 | else 661 | file.reset(new std::ofstream(*iter)); 662 | } 663 | half_test test(file ? *file : std::cout, fast); 664 | 665 | timer time; 666 | return test.test(); 667 | } 668 | -------------------------------------------------------------------------------- /web/Mainpage.md: -------------------------------------------------------------------------------- 1 | Half-precision floating point library {#mainpage} 2 | ===================================== 3 | 4 | This is a C++ header-only library to provide an [IEEE 754](http://en.wikipedia.org/wiki/IEEE_754-2008) conformant 16-bit [half-precision](http://en.wikipedia.org/wiki/Half_precision_floating-point_format) floating point type along with corresponding arithmetic operators, type conversions and common mathematical functions. It aims for both efficiency and ease of use, trying to accurately mimic the behaviour of the builtin floating point types at the best performance possible. It is hosted on [SourceForge.net](http://sourceforge.net/projects/half/). 5 | 6 | [TOC] 7 | 8 | 9 | News {#new} 10 | ==== 11 | 12 | March 6, 2017 - Release 1.12.0 13 | ------------------------------ 14 | 15 | [Version 1.12.0](http://sourceforge.net/projects/half/files/half/1.12.0) of the library has been released. It changes the behaviour of half_cast() when casting to/from builtin floating point types. Previously those were performed by an explicit intermediary cast to/from `float`. But this could lead to imprecise results, since the rounding from `double`/`long double` to `float` was not controlled by the rounding mode of the half_cast(). Now each half_cast() always rounds directly to/from the specified type using the given rounding mode and thus guarantees exact compliance to this rounding mode. Furthermore, a minor portability issue with logb() and ilogb() has been fixed, that could cause trouble on non-twos-complement implementations (if there are any at all). It was also tested for *MS Visual C++ 2015*. 16 | 17 | November 16, 2013 - Release 1.11.0 18 | --------------------------------- 19 | 20 | [Version 1.11.0](http://sourceforge.net/projects/half/files/half/1.11.0) of the library has been released. It further increases the flexibility of the rounding, by allowing the round to nearest behaviour to be configured more precisely. By default half-way cases during round to nearest are rounded away from zero (and thus analogous to the round() function), but by redefining [HALF_ROUND_TIES_TO_EVEN](\ref HALF_ROUND_TIES_TO_EVEN) to `1` this can be changed to the slower but less biased round to even. In addition to that the support for C++11 mathematical functions in light of unsupported single-precision versions has been completed by providing erf(), erfc(), lgamma() and tgamma() even if their `` counterparts are unavailable. Furthermore, it fixes a bug that made it impossible to disable support for C++11 mathematical functions in *VC++ 2013*. 21 | 22 | [more](news.html) 23 | 24 | 25 | ------------------------- 26 | Download and Installation {#downloads} 27 | ========================= 28 | 29 | The library in its most recent version can be obtained from here, see the [Release Notes](changelog.html) for further information: 30 | 31 |
  • [Download half 1.12.0 (.zip)](http://sourceforge.net/projects/half/files/latest/download)
32 | 33 | If you are interested in previous versions of the library, see the [SourceForge download page](http://sourceforge.net/projects/half/files/half). 34 | 35 | Comfortably enough, the library consists of just a single header file containing all the functionality, which can be directly included by your projects, without the neccessity to build anything or link to anything. 36 | 37 | Whereas this library is fully C++98-compatible, it can profit from certain C++11 features. Support for those features is checked and enabled automatically at compile (or rather preprocessing) time, but can be explicitly enabled or disabled by defining the corresponding preprocessor symbols to either 1 or 0 yourself. This is useful when the automatic detection fails (for more exotic implementations) or when a feature should be explicitly disabled: 38 | 39 | C++11 feature | Used for | Enabled for (and newer) | Override with 40 | -------------------------------------|------------------------------------|---------------------------------------------|---------------------------------- 41 | `long long` integer type | functions returning `long long` | *VC++ 2003*, *gcc*, *clang* | `HALF_ENABLE_CPP11_LONG_LONG` 42 | static assertions | extended compile-time checks | *VC++ 2010*, *gcc 4.3*, *clang 2.9* | `HALF_ENABLE_CPP11_STATIC_ASSERT` 43 | generalized constant expressions | constant operations | *VC++ 2015*, *gcc 4.6*, *clang 3.1* | `HALF_ENABLE_CPP11_CONSTEXPR` 44 | `noexcept` specifications | proper `noexcept` functions | *VC++ 2015*, *gcc 4.6*, *clang 3.0* | `HALF_ENABLE_CPP11_NOEXCEPT` 45 | user-defined literals | half-precision literals | *VC++ 2015*, *gcc 4.7*, *clang 3.1* | `HALF_ENABLE_CPP11_USER_LITERALS` 46 | type traits from `` | TMP and extended checks | *VC++ 2010*, *libstdc++ 4.3*, libc++ | `HALF_ENABLE_CPP11_TYPE_TRAITS` 47 | sized integer types from `` | more flexible type sizes | *VC++ 2010*, *libstdc++ 4.3*, libc++ | `HALF_ENABLE_CPP11_CSTDINT` 48 | certain new `` functions | corresponding half implementations | *VC++ 2013*, *libstdc++ 4.3*, libc++ | `HALF_ENABLE_CPP11_CMATH` 49 | `std::hash` from `` | hash function for halfs | *VC++ 2010*, *libstdc++ 4.3*, libc++ | `HALF_ENABLE_CPP11_HASH` 50 | 51 | The library has been tested successfully with *Visual C++ 2005* - *2015*, *gcc 4.4* - *4.8* and *clang 3.1*. Please [contact me](#contact) if you have any problems, suggestions or even just success testing it on other platforms. 52 | 53 | 54 | ------------- 55 | Documentation {#doc} 56 | ============= 57 | 58 | What follows are some general words about the usage of the library and its implementation. For a complete reference documentation of its iterface you should consult the [API Documentation](usergroup0.html). 59 | 60 | 61 | Basic usage {#usage} 62 | ----------- 63 | 64 | To make use of the library just include its only header file half.hpp, which defines all half-precision functionality inside the half_float namespace. The actual 16-bit half-precision data type is represented by the [half](\ref half_float::half) type. This type behaves like the builtin floating point types as much as possible, supporting the usual arithmetic, comparison and streaming operators, which makes its use pretty straight-forward: 65 | 66 | ~~~~{.cpp} 67 | using half_float::half; 68 | half a(3.4), b(5); 69 | half c = a * b; 70 | c += 3; 71 | if(c > a) 72 | std::cout << c << std::endl; 73 | ~~~~ 74 | 75 | Additionally the half_float namespace also defines half-precision versions for all mathematical functions of the [C++ standard library](http://en.cppreference.com/w/cpp/numeric/math), which can be used directly through ADL: 76 | 77 | ~~~~{.cpp} 78 | half a(-3.14159); 79 | half s = sin(abs(a)); 80 | long l = lround(s); 81 | ~~~~ 82 | 83 | You may also specify explicit half-precision literals, since the library provides a user-defined literal inside the half_float::literal namespace, which you just need to import (assuming support for C++11 user-defined literals): 84 | 85 | ~~~~{.cpp} 86 | using namespace half_float::literal; 87 | half x = 1.0_h; 88 | ~~~~ 89 | 90 | Furthermore the library provides proper specializations for `std::numeric_limits`, defining various implementation properties, and `std::hash` for hashing half-precision numbers (assuming support for C++11 `std::hash`). Similar to the corresponding preprocessor symbols from `` the library also defines the [HUGE_VALH](\ref HUGE_VALH) constant and maybe the [FP_FAST_FMAH](\ref FP_FAST_FMAH) symbol. 91 | 92 | Conversions and rounding {#conversions} 93 | ------------------------ 94 | 95 | The [half](\ref half_float::half) is explicitly constructible/convertible from a single-precision `float` argument. Thus it is also explicitly constructible/convertible from any type implicitly convertible to `float`, but constructing it from types like `double` or `int` will involve the usual warnings arising when implicitly converting those to `float` because of the lost precision. On the one hand those warnings are intentional, because converting those types to [half](\ref half_float::half) neccessarily also reduces precision. But on the other hand they are raised for explicit conversions from those types, when the user knows what he is doing. So if those warnings keep bugging you, then you won't get around first explicitly converting to `float` before converting to [half](\ref half_float::half), or use the half_cast() described below. In addition you can also directly assign `float` values to [half](\ref half_float::half)s. 96 | 97 | In contrast to the float-to-half conversion, which reduces precision, the conversion from [half](\ref half_float::half) to `float` (and thus to any other type implicitly convertible from `float`) is implicit, because all values represetable with half-precision are also representable with single-precision. This way the half-to-float conversion behaves similar to the builtin float-to-double conversion and all arithmetic expressions involving both half-precision and single-precision arguments will be of single-precision type. This way you can also directly use the mathematical functions of the C++ standard library, though in this case you will invoke the single-precision versions which will also return single-precision values, which is (even if maybe performing the exact same computation, see below) not as conceptually clean when working in a half-precision environment. 98 | 99 | The default rounding mode for conversions from `float` to [half](\ref half_float::half) uses truncation (round toward zero, but mapping overflows to infinity) for rounding values not representable exactly in half-precision. This is the fastest rounding possible and is usually sufficient. But by redefining the [HALF_ROUND_STYLE](\ref HALF_ROUND_STYLE) preprocessor symbol (before including half.hpp) this default can be overridden with one of the other standard rounding modes using their respective constants or the equivalent values of `std::float_round_style` (it can even be synchronized with the underlying single-precision implementation by defining it to `std::numeric_limits::round_style`): 100 | 101 | `std::float_round_style` | value | rounding 102 | ---------------------------------|-------|------------------------- 103 | `std::round_indeterminate` | -1 | fastest (default) 104 | `std::round_toward_zero` | 0 | toward zero 105 | `std::round_to_nearest` | 1 | to nearest 106 | `std::round_toward_infinity` | 2 | toward positive infinity 107 | `std::round_toward_neg_infinity` | 3 | toward negative infinity 108 | 109 | In addition to changing the overall default rounding mode one can also use the half_cast(). This converts between [half](\ref half_float::half) and any built-in arithmetic type using a configurable rounding mode (or the default rounding mode if none is specified). In addition to a configurable rounding mode, half_cast() has another big difference to a mere `static_cast`: Any conversions are performed directly using the given rounding mode, without any intermediate conversion to/from `float`. This is especially relevant for conversions to integer types, which don't necessarily truncate anymore. But also for conversions from `double` or `long double` this may produce more precise results than a pre-conversion to `float` using the single-precision implementation's current rounding mode would. 110 | 111 | ~~~~{.cpp} 112 | half a = half_cast(4.2); 113 | half b = half_cast::round_style>(4.2f); 114 | assert( half_cast( 0.7_h ) == 1 ); 115 | assert( half_cast( 4097 ) == 4096.0_h ); 116 | assert( half_cast( 4097 ) == 4100.0_h ); 117 | assert( half_cast( std::numeric_limits::min() ) > 0.0_h ); 118 | ~~~~ 119 | 120 | When using round to nearest (either as default or through half_cast()) ties are by default resolved by rounding them away from zero (and thus equal to the behaviour of the round() function). But by redefining the [HALF_ROUND_TIES_TO_EVEN](\ref HALF_ROUND_TIES_TO_EVEN) preprocessor symbol to `1` (before including half.hpp) this default can be changed to the slightly slower but less biased and more IEEE-conformant behaviour of rounding half-way cases to the nearest even value. 121 | 122 | ~~~~{.cpp} 123 | #define HALF_ROUND_TIES_TO_EVEN 1 124 | #include 125 | ... 126 | assert( half_cast(3.5_h) 127 | == half_cast(4.5_h) ); 128 | ~~~~ 129 | 130 | Implementation {#implementation} 131 | -------------- 132 | 133 | For performance reasons (and ease of implementation) many of the mathematical functions provided by the library as well as all arithmetic operations are actually carried out in single-precision under the hood, calling to the C++ standard library implementations of those functions whenever appropriate, meaning the arguments are converted to `float`s and the result back to [half](\ref half_float::half). But to reduce the conversion overhead as much as possible any temporary values inside of lengthy expressions are kept in single-precision as long as possible, while still maintaining a strong half-precision type to the outside world. Only when finally assigning the value to a [half](\ref half_float::half) or calling a function that works directly on [half](\ref half_float::half)s is the actual conversion done (or never, when further converting the result to `float`). 134 | 135 | This approach has two implications. First of all you have to treat the documentation on this site as a simplified version, describing the behaviour of the library as if implemented this way. The actual argument and return types of functions and operators may involve other internal types (feel free to generate the exact developer documentation from the Doxygen comments in the library's header file if you really need to). But nevertheless the behaviour is exactly like specified in the documentation. The other implication is, that in the presence of rounding errors or over-/underflows arithmetic expressions may produce different results when compared to converting to half-precision after each individual operation: 136 | 137 | ~~~~{.cpp} 138 | half a = std::numeric_limits::max() * 2.0_h / 2.0_h; // a = MAX 139 | half b = half(std::numeric_limits::max() * 2.0_h) / 2.0_h; // b = INF 140 | assert( a != b ); 141 | ~~~~ 142 | 143 | But this should only be a problem in very few cases. One last word has to be said when talking about performance. Even with its efforts in reducing conversion overhead as much as possible, the software half-precision implementation can most probably not beat the direct use of single-precision computations. Usually using actual `float` values for all computations and temproraries and using [half](\ref half_float::half)s only for storage is the recommended way. On the one hand this somehow makes the provided mathematical functions obsolete (especially in light of the implicit conversion from [half](\ref half_float::half) to `float`), but nevertheless the goal of this library was to provide a complete and conceptually clean half-precision implementation, to which the standard mathematical functions belong, even if usually not needed. 144 | 145 | IEEE conformance {#ieee} 146 | ---------------- 147 | 148 | The [half](\ref half_float::half) type uses the standard IEEE representation with 1 sign bit, 5 exponent bits and 10 mantissa bits (11 when counting the hidden bit). It supports all types of special values, like subnormal values, infinity and NaNs. But there are some limitations to the complete conformance to the IEEE 754 standard: 149 | 150 | - The implementation does not differentiate between signalling and quiet NaNs, this means operations on [half](\ref half_float::half)s are not specified to trap on signalling NaNs (though they may, see last point). 151 | - Though arithmetic operations are internally rounded to single-precision using the underlying single-precision implementation's current rounding mode, those values are then converted to half-precision using the default half-precision rounding mode (changed by defining [HALF_ROUND_STYLE](\ref HALF_ROUND_STYLE) and [HALF_ROUND_TIES_TO_EVEN](\ref HALF_ROUND_TIES_TO_EVEN) accordingly). This mixture of rounding modes is also the reason why [std::numeric_limits::round_style](\ref std::numeric_limits::round_style) may actually return `std::round_indeterminate` when half- and single-precision rounding modes don't match. 152 | - Because of internal truncation it may also be that certain single-precision NaNs will be wrongly converted to half-precision infinity, though this is very unlikely to happen, since most single-precision implementations don't tend to only set the lowest bits of a NaN mantissa. 153 | - The implementation does not provide any floating point exceptions, thus arithmetic operations or mathematical functions are not specified to invoke proper floating point exceptions. But due to many functions implemented in single-precision, those may still invoke floating point exceptions of the underlying single-precision implementation. 154 | 155 | Some of those points could have been circumvented by controlling the floating point environment using `` or implementing a similar exception mechanism. But this would have required excessive runtime checks giving two high an impact on performance for something that is rarely ever needed. If you really need to rely on proper floating point exceptions, it is recommended to explicitly perform computations using the built-in floating point types to be on the safe side. In the same way, if you really need to rely on a particular rounding behaviour, it is recommended to either use single-precision computations and explicitly convert the result to half-precision using half_cast() and specifying the desired rounding mode, or synchronize the default half-precision rounding mode to the rounding mode of the single-precision implementation (most likely `HALF_ROUND_STYLE=1`, `HALF_ROUND_TIES_TO_EVEN=1`). But this is really considered an expert-scenario that should be used only when necessary, since actually working with half-precision usually comes with a certain tolerance/ignorance of exactness considerations and proper rounding comes with a certain performance cost. 156 | 157 | 158 | ------------------- 159 | Credits and Contact {#contact} 160 | =================== 161 | 162 | This library is developed by [Christian Rau](http://sourceforge.net/users/rauy) and released under the [MIT License](LICENSE.txt). If you have any questions or problems with it, feel free to contact me at [rauy AT users.sourceforge.net](mailto:rauy@users.sourceforge.net) or use any of the other means for [support](usergroup1.html). 163 | 164 | Additional credit goes to **Jeroen van der Zijp** for his paper on [Fast Half Float Conversions](ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf), whose algorithms have been used in the library for converting between half-precision and single-precision values. 165 | -------------------------------------------------------------------------------- /web/News.md: -------------------------------------------------------------------------------- 1 | News {#news} 2 | ==== 3 | 4 | March 6, 2017 - Release 1.12.0 5 | ------------------------------ 6 | 7 | [Version 1.12.0](http://sourceforge.net/projects/half/files/half/1.12.0) of the library has been released. It changes the behaviour of half_cast() when casting to/from builtin floating point types. Previously those were performed by an explicit intermediary cast to/from `float`. But this could lead to imprecise results, since the rounding from `double`/`long double` to `float` was not controlled by the rounding mode of the half_cast(). Now each half_cast() always rounds directly to/from the specified type using the given rounding mode and thus guarantees exact compliance to this rounding mode. Furthermore, a minor portability issue with logb() and ilogb() has been fixed, that could cause trouble on non-twos-complement implementations (if there are any at all). It was also tested for *MS Visual C++ 2015*. 8 | 9 | ---------------------------------- 10 | November 16, 2013 - Release 1.11.0 11 | ---------------------------------- 12 | 13 | [Version 1.11.0](http://sourceforge.net/projects/half/files/half/1.11.0) of the library has been released. It further increases the flexibility of the rounding, by allowing the round to nearest behaviour to be configured more precisely. By default half-way cases during round to nearest are rounded away from zero (and thus analogous to the round() function), but by redefining [HALF_ROUND_TIES_TO_EVEN](\ref HALF_ROUND_TIES_TO_EVEN) to `1` this can be changed to the slower but less biased round to even. In addition to that the support for C++11 mathematical functions in light of unsupported single-precision versions has been completed by providing erf(), erfc(), lgamma() and tgamma() even if their `` counterparts are unavailable. Furthermore, it fixes a bug that made it impossible to disable support for C++11 mathematical functions in *VC++ 2013*. 14 | 15 | --------------------------------- 16 | November 9, 2013 - Release 1.10.0 17 | --------------------------------- 18 | 19 | [Version 1.10.0](http://sourceforge.net/projects/half/files/half/1.10.0) of the library has been released. It adds the possibility of changing the default rounding mode for halfs (used for any float-to-half conversion) at compile-time by redefining the [HALF_ROUND_STYLE](\ref HALF_ROUND_STYLE) preprocessor symbol. In addition to that the behaviour of the half_cast() function was adjusted to respect the specified rounding mode for conversions to/from integer types, without a roundtrip over an additional conversion to/from `float`. The half_cast() now only supports built-in arithmetic types (apart from [half](\ref half_float::half)s, of course) and any further conversions from them to custom types have to be done explicitly. The usage and checks of C++11 features has been extended by support for type traits and TMP facilities from ``, controllable with the `HALF_ENABLE_CPP11_TYPE_TRAITS` symbol. Last but not least, the library now supports non-IEEE single-precision implementations, which are pretty unlikely nowadays, though. 20 | 21 | -------------------------------- 22 | November 1, 2013 - Release 1.9.2 23 | -------------------------------- 24 | 25 | [Version 1.9.2](http://sourceforge.net/projects/half/files/half/1.9.2) of the library has been released. It was tested and fixed for *MS Visual C++ 2013* and *gcc 4.8*. In addition to that it removes some warnings on *MSVC* compilers in general. 26 | 27 | ------------------------------ 28 | August 8, 2013 - Release 1.9.1 29 | ------------------------------ 30 | 31 | [Version 1.9.1](http://sourceforge.net/projects/half/files/half/1.9.1) of the library has been released. It fixes compilation problems with older *gcc* and *MSVC* versions. Furthermore it adds a small fix to the non-C++11 implementations of remainder() and remquo(), which could cause a missing symbol on implementations that do not bring `` functions into global namespace. 32 | 33 | ------------------------------ 34 | August 7, 2013 - Release 1.9.0 35 | ------------------------------ 36 | 37 | [Version 1.9.0](http://sourceforge.net/projects/half/files/half/1.9.0) of the library has been released. This version fixes the behaviour of the half-precsion C++11 functions `nearbyint`, `rint`, `lrint` and `llrint`. Formerly those functions were implemented in terms of their respective single-precision versions from `` (and thus were only supported if the single-precision versions were available, too) and were thus using the current rounding mode of the underlying single-precision implementation. But it is conceptually more correct for those functions to use the rounding mode of the half-precision implementation (truncation). So now those functions are always supported and return the nearest integer according to [half](\ref half_float::half)'s internal rounding mode and thus behave equivalently to trunc() and `static_cast` respectively. Furthermore the support for C++11 mathematical functions in light of unsupported single-precision versions has been increased further, by providing remainder(), remquo() and cbrt() even if their `` counterparts are unavailable. 38 | 39 | -------------------------------- 40 | January 22, 2013 - Release 1.8.1 41 | -------------------------------- 42 | 43 | [Version 1.8.1](http://sourceforge.net/projects/half/files/half/1.8.1) of the library has been released. This just fixes a compile error when including `half.hpp` in multiple files, resulting in multiple definitions of the nanh() function due to a missing `inline` specification. 44 | 45 | -------------------------------- 46 | January 19, 2013 - Release 1.8.0 47 | -------------------------------- 48 | 49 | [Version 1.8.0](http://sourceforge.net/projects/half/files/half/1.8.0) of the library has been released. It adds support for a bunch of additional C++11 mathematical functions even if their single-precision counterparts are not supported, in particular exponential and logarithmic functions (exp2(), expm1(), log2(), log1p()), hyperbolic area functions (asinh(), acosh(), atanh()) and the hypotenuse function (hypot()). The fma() function now uses the default single-precision implementation even if the single-precision version from `` is available but not faster than the straight-forward implementation. Thus it is now always at least equally fast to the manual half-precision `x*y + z` operation (yet being correctly rounded as a single operation) and thus [FP_FAST_FMAH](\ref FP_FAST_FMAH) practically always defined. 50 | 51 | Furthermore, the internal expression implementation has been completely revised. This fixes issues with overload resolution which could occur when trying to call certain mathematical functions by unqualified invocation (relying on `using` declarations or ADL) and led to ambiguities or the incorrect preference of the standard library functions over the half-precision versions. 52 | 53 | -------------------------------- 54 | October 26, 2012 - Release 1.7.0 55 | -------------------------------- 56 | 57 | [Version 1.7.0](http://sourceforge.net/projects/half/files/half/1.7.0) of the library has been released. It adds support for C++11 `noexcept` specifications. But due to the ongoing discussions about their appropriate usage in practice (and the author's limited experience with them) they are at the moment only used to provide a C++11-conformant `std::numeric_limits` specialization, with all its functions returning half-preicision constants now properly being `noexcept`. Furthermore, the automatic support for C++11 `long long` and the corresponding mathematical functions on *Microsoft* compilers has been extended all the way down to *VC++ 2003*. 58 | 59 | ---------------------------------- 60 | September 13, 2012 - Release 1.6.1 61 | ---------------------------------- 62 | 63 | [Version 1.6.1](http://sourceforge.net/projects/half/files/half/1.6.1) of the library has been released. It makes the fma() and fdim() functions available even if the corresponding single-precision functions from C++11 `` are not supported. 64 | 65 | ---------------------------------- 66 | September 12, 2012 - Release 1.6.0 67 | ---------------------------------- 68 | 69 | [Version 1.6.0](http://sourceforge.net/projects/half/files/half/1.6.0) of the library has been released. It fixes a major bug in the C++98 compatibility for non-VC compilers, which required C++11 `` functions even without C++11 support enabled. Furthermore, an additional preprocessor flag `HALF_ENABLE_CPP11_LONG_LONG` has been added, which controls the support for C++11 `long long` integers and the corresponding mathematical functions (actually only llround()). 70 | 71 | ------------------------------- 72 | August 17, 2012 - Release 1.5.1 73 | ------------------------------- 74 | 75 | [Version 1.5.1](http://sourceforge.net/projects/half/files/half/1.5.1) of the library has been released. It fixes the `std::numeric_limits` specialization to always return `std::round_indeterminate` as `round_style`, even if the `float` version returns `std::round_toward_zero`. This is neccessary as the single-to-half conversion is not exactly round-toward-zero, since it maps overflows to +/-infinity instead of the maximum/minimum finite value. 76 | 77 | ------------------------------- 78 | August 16, 2012 - Release 1.5.0 79 | ------------------------------- 80 | 81 | [Version 1.5.0](http://sourceforge.net/projects/half/files/half/1.5.0) of the library has been released. It adds a special half_cast() that can be used to cast between [half](\ref half_float::half) and any type convertible to/from `float`. In addition to doing an explicit conversion via `float` and thus avoiding any possible warnings about precision loss, it allows the explicit specification of the rounding mode to use for the single-to-half conversion (if any). This way you can choose a specific rounding mode if needed and can even synchronize it with the rounding mode of the underlying single-precision implementation (which is usually `std::round_to_nearest`). But this is more of an expert feature to be used when you are sure you really need it (which should rarely be the case) and most of the time the default rounding from single- to half-precision (`std::round_indeterminate`), which is the fastest, will be sufficient. Furthermore, the library has been tested successfully with Visual C++ 2008. 82 | 83 | ------------------------------- 84 | August 12, 2012 - Release 1.4.0 85 | ------------------------------- 86 | 87 | [Version 1.4.0](http://sourceforge.net/projects/half/files/half/1.4.0) of the library has been released. It adds support for C++11 generalized constant expressions (`constexpr`). But due to the not constantly expressable half-single-conversions most arithmetic operators as well as the half-precision literals cannot be made `constexpr`. The only `constexpr` operators are the unary plus and minus as well as the zero-initializing default constructor. But now the `std::numeric_limits` specialization is C++11-conformant, with all its special half-precision constants being actual constant expressions. 88 | 89 | ------------------------------- 90 | August 11, 2012 - Release 1.3.1 91 | ------------------------------- 92 | 93 | [Version 1.3.1](http://sourceforge.net/projects/half/files/half/1.3.1) of the library has been released. It fixes a bug with non-VC compilers that required the presence of `std::isnan` and `std::signbit` even if C++11 `` functions are unsupported/disabled. Furthermore the library has been tested successfully with Visual C++ 2005 and 2012. 94 | 95 | ------------------------------- 96 | August 10, 2012 - Release 1.3.0 97 | ------------------------------- 98 | 99 | [Version 1.3.0](http://sourceforge.net/projects/half/files/half/1.3.0) of the library has been released. It makes the requirement for C++11's `` and `static_assert` optional and thus is now comletely C++98-compatible. Furthermore, all the C++11 features used by the library and detected automatically are now overridable by the user, by just defining the corresponding preprocessor symbols to 0 or 1, which is useful in cases where the automatic detection fails or where the support for a feature should be explicitly disabled. 100 | 101 | ------------------------------ 102 | August 7, 2012 - Release 1.2.0 103 | ------------------------------ 104 | 105 | [Version 1.2.0](http://sourceforge.net/projects/half/files/half/1.2.0) of the library has been released. It adds preprocessor definitions for [HUGE_VALH](\ref HUGE_VALH) and (maybe) [FP_FAST_FMAH](\ref FP_FAST_FMAH) in correspondence with their respective single-precision counterparts from ``. It also fixes the preprocessor symbols it uses internally to be undefined properly after their use. Furthermore, the library has been tested successfully with *clang 3.1*. 106 | 107 | ------------------------------ 108 | August 7, 2012 - Release 1.1.2 109 | ------------------------------ 110 | 111 | [Version 1.1.2](http://sourceforge.net/projects/half/files/half/1.1.2) of the library has been released. It fixes the `std::numeric_limits` specialization further, enabling it to return `std::round_toward_zero` instead of `std::round_indeterminate` when possible (though this is very unlikely). Additionally the `round_error()` has been corrected to reflect the worst-case round-toward-zero behaviour. Furthermore, the library has been tested successfully with *gcc 4.5*. 112 | 113 | ------------------------------ 114 | August 6, 2012 - Release 1.1.1 115 | ------------------------------ 116 | 117 | [Version 1.1.1](http://sourceforge.net/projects/half/files/half/1.1.1) of the library has been released. It includes a minor fix to the `std::numeric_limits` specialization, which now returns a normalized number for `min()` according to the C++ standard. Additionally the `round_style` is now `std::round_indeterminate` due to the mixture of internal single-precision rounding with float-to-half truncation. 118 | 119 | ------------------------------ 120 | August 6, 2012 - Release 1.1.0 121 | ------------------------------ 122 | 123 | [Version 1.1.0](http://sourceforge.net/projects/half/files/half/1.1.0) of the library has been released. It provides support for explicit half-precision literals using C++11's user-defined literals. It has been tested successfully with *gcc 4.7*. 124 | 125 | ------------------------------------ 126 | August 5, 2012 - First release 1.0.0 127 | ------------------------------------ 128 | 129 | The first official release, [version 1.0.0](http://sourceforge.net/projects/half/files/half/1.0.0), of the library is finally out. 130 | 131 | --------------------------------------------- 132 | August 1, 2012 - Code and Project-Web release 133 | --------------------------------------------- 134 | 135 | The first version of the library has been checked into source control and is thus available to the public through the [SVN repository](http://sourceforge.net/p/half/code/), though still waiting for an explicit file release. Additionally the project web containing the library's documentation went online. 136 | 137 | -------------------------------- 138 | July 30, 2012 - Project Kick-off 139 | -------------------------------- 140 | 141 | The **half** project has finally been registered on [Sourceforge.net](http://sourceforge.net/projects/half/). 142 | -------------------------------------------------------------------------------- /web/half.hpp: -------------------------------------------------------------------------------- 1 | // half - IEEE 754-based half-precision floating point library. 2 | // 3 | // Copyright (c) 2012-2017 Christian Rau 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 6 | // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 7 | // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 13 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 15 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | 17 | // This is a dummy header file to provide a clean interface documentation to Doxygen, without any ugly internals. 18 | 19 | /// \file 20 | /// Main header file of the library. 21 | 22 | 23 | /// Default rounding mode. 24 | /// This specifies the rounding mode used for all conversions between [half](\ref half_float::half)s and `float`s as well as 25 | /// for the half_cast() if not specifying a rounding mode explicitly. It can be redefined (before including `half.hpp`) to one 26 | /// of the standard rounding modes using their respective constants or the equivalent values of 27 | /// [std::float_round_style](http://en.cppreference.com/w/cpp/types/numeric_limits/float_round_style): 28 | /// 29 | /// `std::float_round_style` | value | rounding 30 | /// ---------------------------------|-------|------------------------- 31 | /// `std::round_indeterminate` | -1 | fastest (default) 32 | /// `std::round_toward_zero` | 0 | toward zero 33 | /// `std::round_to_nearest` | 1 | to nearest 34 | /// `std::round_toward_infinity` | 2 | toward positive infinity 35 | /// `std::round_toward_neg_infinity` | 3 | toward negative infinity 36 | /// 37 | /// By default this is set to `-1` (`std::round_indeterminate`), which uses truncation (round toward zero, but with overflows 38 | /// set to infinity) and is the fastest rounding mode possible. It can even be set to 39 | /// [std::numeric_limits::round_style](http://en.cppreference.com/w/cpp/types/numeric_limits/round_style) to synchronize 40 | /// the rounding mode with that of the underlying single-precision implementation. 41 | #define HALF_ROUND_STYLE -1 42 | 43 | /// Tie-breaking behaviour for round to nearest. 44 | /// This specifies if ties in round to nearest should be resolved by rounding to the nearest even value. By default this is 45 | /// defined to `0` resulting in the faster but slightly more biased behaviour of rounding away from zero in half-way cases (and 46 | /// thus equal to the round() function), but can be redefined to `1` (before including half.hpp) if more IEEE-conformant 47 | /// behaviour is needed. 48 | #define HALF_ROUND_TIES_TO_EVEN 0 49 | 50 | /// Value signaling overflow. 51 | /// In correspondence with `HUGE_VAL[F|L]` from `` this symbol expands to a positive value signaling the overflow of an 52 | /// operation, in particular it just evaluates to positive infinity. 53 | /// 54 | /// **See also:** Documentation for [HUGE_VAL](http://en.cppreference.com/w/cpp/numeric/math/HUGE_VAL) 55 | #define HUGE_VALH std::numeric_limits::infinity() 56 | 57 | /// Fast half-precision fma function. 58 | /// This symbol is only defined if the fma() function generally executes as fast as, or faster than, a separate 59 | /// half-precision multiplication followed by an addition. Due to the internal single-precision implementation of all 60 | /// arithmetic operations, this is in fact always the case. 61 | /// 62 | /// **See also:** Documentation for [FP_FAST_FMA](http://en.cppreference.com/w/cpp/numeric/math/fma) 63 | #define FP_FAST_FMAH 1 64 | 65 | 66 | /// Main namespace for half precision functionality. 67 | /// This namespace contains all the functionality provided by the library. 68 | namespace half_float 69 | { 70 | /// Half-precision floating point type. 71 | /// This class implements an IEEE-conformant half-precision floating point type with the usual arithmetic operators and 72 | /// conversions. It is implicitly convertible to single-precision floating point, which makes artihmetic expressions and 73 | /// functions with mixed-type operands to be of the most precise operand type. Additionally all arithmetic operations 74 | /// (and many mathematical functions) are carried out in single-precision internally. All conversions from single- to 75 | /// half-precision are done using the library's default rounding mode, but temporary results inside chained arithmetic 76 | /// expressions are kept in single-precision as long as possible (while of course still maintaining a strong half-precision type). 77 | /// 78 | /// According to the C++98/03 definition, the half type is not a POD type. But according to C++11's less strict and 79 | /// extended definitions it is both a standard layout type and a trivially copyable type (even if not a POD type), which 80 | /// means it can be standard-conformantly copied using raw binary copies. But in this context some more words about the 81 | /// actual size of the type. Although the half is representing an IEEE 16-bit type, it does not neccessarily have to be of 82 | /// exactly 16-bits size. But on any reasonable implementation the actual binary representation of this type will most 83 | /// probably not ivolve any additional "magic" or padding beyond the simple binary representation of the underlying 16-bit 84 | /// IEEE number, even if not strictly guaranteed by the standard. But even then it only has an actual size of 16 bits if 85 | /// your C++ implementation supports an unsigned integer type of exactly 16 bits width. But this should be the case on 86 | /// nearly any reasonable platform. 87 | /// 88 | /// So if your C++ implementation is not totally exotic or imposes special alignment requirements, it is a reasonable 89 | /// assumption that the data of a half is just comprised of the 2 bytes of the underlying IEEE representation. 90 | struct half 91 | { 92 | /// \name Construction and assignment 93 | /// \{ 94 | 95 | /// Default constructor. 96 | /// This initializes the half to 0. Although this does not match the builtin types' default-initialization semantics 97 | /// and may be less efficient than no initialization, it is needed to provide proper value-initialization semantics. 98 | constexpr half() noexcept; 99 | 100 | /// Conversion constructor. 101 | /// \param rhs float to convert 102 | explicit half(float rhs); 103 | 104 | /// Conversion to single-precision. 105 | /// \return single precision value 106 | operator float() const; 107 | 108 | /// Single-precision assignment. 109 | /// \param rhs single-precision value to copy from 110 | /// \return reference to this half 111 | half& operator=(float rhs); 112 | 113 | /// \} 114 | /// \name Arithmetic updates 115 | /// \{ 116 | 117 | /// Arithmetic assignment. 118 | /// This operation uses the underlying single-precision implementation. 119 | /// \tparam E type of concrete half expression 120 | /// \param rhs half to add 121 | /// \return reference to this half 122 | half& operator+=(half rhs); 123 | 124 | /// Arithmetic assignment. 125 | /// This operation uses the underlying single-precision implementation. 126 | /// \tparam E type of concrete half expression 127 | /// \param rhs half to subtract 128 | /// \return reference to this half 129 | half& operator-=(half rhs); 130 | 131 | /// Arithmetic assignment. 132 | /// This operation uses the underlying single-precision implementation. 133 | /// \tparam E type of concrete half expression 134 | /// \param rhs half to multiply with 135 | /// \return reference to this half 136 | half& operator*=(half rhs); 137 | 138 | /// Arithmetic assignment. 139 | /// This operation uses the underlying single-precision implementation. 140 | /// \tparam E type of concrete half expression 141 | /// \param rhs half to divide by 142 | /// \return reference to this half 143 | half& operator/=(half rhs); 144 | 145 | /// Arithmetic assignment. 146 | /// This operation uses the underlying single-precision implementation. 147 | /// \param rhs single-precision value to add 148 | /// \return reference to this half 149 | half& operator+=(float rhs); 150 | 151 | /// Arithmetic assignment. 152 | /// This operation uses the underlying single-precision implementation. 153 | /// \param rhs single-precision value to subtract 154 | /// \return reference to this half 155 | half& operator-=(float rhs); 156 | 157 | /// Arithmetic assignment. 158 | /// This operation uses the underlying single-precision implementation. 159 | /// \param rhs single-precision value to multiply with 160 | /// \return reference to this half 161 | half& operator*=(float rhs); 162 | 163 | /// Arithmetic assignment. 164 | /// This operation uses the underlying single-precision implementation. 165 | /// \param rhs single-precision value to divide by 166 | /// \return reference to this half 167 | half& operator/=(float rhs); 168 | 169 | /// \} 170 | /// \name Increment and decrement 171 | /// \{ 172 | 173 | /// Prefix increment. 174 | /// This operation uses the underlying single-precision implementation. 175 | /// \return incremented half value 176 | half& operator++(); 177 | 178 | /// Prefix decrement. 179 | /// This operation uses the underlying single-precision implementation. 180 | /// \return decremented half value 181 | half& operator--(); 182 | 183 | /// Postfix increment. 184 | /// This operation uses the underlying single-precision implementation. 185 | /// \return non-incremented half value 186 | half operator++(int); 187 | 188 | /// Postfix decrement. 189 | /// This operation uses the underlying single-precision implementation. 190 | /// \return non-decremented half value 191 | half operator--(int); 192 | /// \} 193 | }; 194 | 195 | 196 | /// \name Comparison operators 197 | /// \{ 198 | 199 | /// Comparison for equality. 200 | /// \param a first operand 201 | /// \param b second operand 202 | /// \retval true if operands equal 203 | /// \retval false else 204 | bool operator==(half a, half b); 205 | 206 | /// Comparison for inequality. 207 | /// \param a first operand 208 | /// \param b second operand 209 | /// \retval true if operands not equal 210 | /// \retval false else 211 | bool operator!=(half a, half b); 212 | 213 | /// Comparison for less than. 214 | /// \param a first operand 215 | /// \param b second operand 216 | /// \retval true if \a a less than \a b 217 | /// \retval false else 218 | bool operator<(half a, half b); 219 | 220 | /// Comparison for greater than. 221 | /// \param a first operand 222 | /// \param b second operand 223 | /// \retval true if \a a greater than \a b 224 | /// \retval false else 225 | bool operator>(half a, half b); 226 | 227 | /// Comparison for less equal. 228 | /// \param a first operand 229 | /// \param b second operand 230 | /// \retval true if \a a less equal \a b 231 | /// \retval false else 232 | bool operator<=(half a, half b); 233 | 234 | /// Comparison for greater equal. 235 | /// \param a first operand 236 | /// \param b second operand 237 | /// \retval true if \a a greater equal \a b 238 | /// \retval false else 239 | bool operator>=(half a, half b); 240 | 241 | /// \} 242 | /// \name Arithmetic operators 243 | /// \{ 244 | 245 | /// Add halfs. 246 | /// This operation uses the underlying single-precision implementation. 247 | /// \param a left operand 248 | /// \param b right operand 249 | /// \return sum of halfs 250 | half operator+(half a, half b); 251 | 252 | /// Subtract halfs. 253 | /// This operation uses the underlying single-precision implementation. 254 | /// \param a left operand 255 | /// \param b right operand 256 | /// \return difference of halfs 257 | half operator-(half a, half b); 258 | 259 | /// Multiply halfs. 260 | /// This operation uses the underlying single-precision implementation. 261 | /// \param a left operand 262 | /// \param b right operand 263 | /// \return product of halfs 264 | half operator*(half a, half b); 265 | 266 | /// Divide halfs. 267 | /// This operation uses the underlying single-precision implementation. 268 | /// \param a left operand 269 | /// \param b right operand 270 | /// \return quotient of halfs 271 | half operator/(half a, half b); 272 | 273 | /// Identity. 274 | /// \param h operand 275 | /// \return uncahnged operand 276 | half constexpr operator+(half h); 277 | 278 | /// Negation. 279 | /// \param h operand 280 | /// \return negated operand 281 | half constexpr operator-(half h); 282 | 283 | /// \} 284 | /// \name Input and output 285 | /// \{ 286 | 287 | /// Output operator. 288 | /// \tparam charT character type 289 | /// \tparam traits character traits 290 | /// \param out output stream to write into 291 | /// \param h half to write 292 | /// \return reference to output stream 293 | template std::basic_ostream& operator<<(std::basic_ostream &out, half h); 294 | 295 | /// Input operator. 296 | /// \tparam charT character type 297 | /// \tparam traits character traits 298 | /// \param in input stream to read from 299 | /// \param h half to read into 300 | /// \return reference to input stream 301 | template std::basic_istream& operator>>(std::basic_istream &in, half &h); 302 | 303 | /// \} 304 | /// \name Basic mathematical operations 305 | /// \{ 306 | 307 | /// Absolute value. 308 | /// \param arg operand 309 | /// \return absolute value of \a arg 310 | half abs(half arg); 311 | 312 | /// Absolute value. 313 | /// \param arg operand 314 | /// \return absolute value of \a arg 315 | half fabs(half arg); 316 | 317 | /// Remainder of division. 318 | /// This function uses the underlying single-precision implementation. 319 | /// \param x first operand 320 | /// \param y second operand 321 | /// \return remainder of floating point division. 322 | half fmod(half x, half y); 323 | 324 | /// Remainder of division. 325 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 326 | /// \param x first operand 327 | /// \param y second operand 328 | /// \return remainder of floating point division. 329 | half remainder(half x, half y); 330 | 331 | /// Remainder of division. 332 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 333 | /// \param x first operand 334 | /// \param y second operand 335 | /// \param quo address to store some bits of quotient at 336 | /// \return remainder of floating point division. 337 | half remquo(half x, half y, int *quo); 338 | 339 | /// Fused multiply add. 340 | /// This function uses the underlying single-precision implementation from C++11 `` if it is supported **and** 341 | /// faster than the straight-forward single-precision implementation (thus if `FP_FAST_FMAF` is defined). 342 | /// \param x first operand 343 | /// \param y second operand 344 | /// \param z third operand 345 | /// \return ( \a x * \a y ) + \a z rounded as one operation. 346 | half fma(half x, half y, half z); 347 | 348 | /// Minimum of halfs. 349 | /// \param x first operand 350 | /// \param y second operand 351 | /// \return minimum of operands 352 | half fmin(half x, half y); 353 | 354 | /// Maximum of halfs. 355 | /// \param x first operand 356 | /// \param y second operand 357 | /// \return maximum of operands 358 | half fmax(half x, half y); 359 | 360 | /// Positive difference. 361 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 362 | /// \param x first operand 363 | /// \param y second operand 364 | /// \return \a x - \a y or 0 if difference negative 365 | half fdim(half x, half y); 366 | 367 | /// Get NaN value. 368 | /// \return quiet NaN 369 | half nanh(const char*); 370 | 371 | /// \} 372 | /// \name Exponential functions 373 | /// \{ 374 | 375 | /// Exponential function. 376 | /// This function uses the underlying single-precision implementation. 377 | /// \param arg function argument 378 | /// \return e raised to \a arg 379 | half exp(half arg); 380 | 381 | /// Binary exponential. 382 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 383 | /// \param arg function argument 384 | /// \return 2 raised to \a arg 385 | half exp2(half arg); 386 | 387 | /// Exponential minus one. 388 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 389 | /// \param arg function argument 390 | /// \return e raised to \a arg and subtracted by 1 391 | half expm1(half arg); 392 | 393 | /// Natural logorithm. 394 | /// This function uses the underlying single-precision implementation. 395 | /// \param arg function argument 396 | /// \return logarithm of \a arg to base e 397 | half log(half arg); 398 | 399 | /// Common logorithm. 400 | /// This function uses the underlying single-precision implementation. 401 | /// \param arg function argument 402 | /// \return logarithm of \a arg to base 10 403 | half log10(half arg); 404 | 405 | /// Natural logorithm. 406 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 407 | /// \param arg function argument 408 | /// \return logarithm of \a arg + 1 to base e 409 | half log1p(half arg); 410 | 411 | /// Binary logorithm. 412 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 413 | /// \param arg function argument 414 | /// \return logarithm of \a arg to base 2 415 | half log2(half arg); 416 | 417 | /// \} 418 | /// \name Power functions 419 | /// \{ 420 | 421 | /// Square root. 422 | /// This function uses the underlying single-precision implementation. 423 | /// \param arg function argument 424 | /// \return square root of \a arg 425 | half sqrt(half arg); 426 | 427 | /// Cubic root. 428 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 429 | /// \param arg function argument 430 | /// \return cubic root of \a arg 431 | half cbrt(half arg); 432 | 433 | /// Hypotenuse function. 434 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 435 | /// \param x first argument 436 | /// \param y second argument 437 | /// \return square root of sum of squares without internal over- or underflows 438 | half hypot(half x, half y); 439 | 440 | /// Power function. 441 | /// This function uses the underlying single-precision implementation. 442 | /// \param base first argument 443 | /// \param exp second argument 444 | /// \return \a base raised to \a exp 445 | half pow(half base, half exp); 446 | 447 | /// \} 448 | /// \name Trigonometric functions 449 | /// \{ 450 | 451 | /// Sine function. 452 | /// This function uses the underlying single-precision implementation. 453 | /// \param arg function argument 454 | /// \return sine value of \a arg 455 | half sin(half arg); 456 | 457 | /// Cosine function. 458 | /// This function uses the underlying single-precision implementation. 459 | /// \param arg function argument 460 | /// \return cosine value of \a arg 461 | half cos(half arg); 462 | 463 | /// Tangent function. 464 | /// This function uses the underlying single-precision implementation. 465 | /// \param arg function argument 466 | /// \return tangent value of \a arg 467 | half tan(half arg); 468 | 469 | /// Arc sine. 470 | /// This function uses the underlying single-precision implementation. 471 | /// \param arg function argument 472 | /// \return arc sine value of \a arg 473 | half asin(half arg); 474 | 475 | /// Arc cosine function. 476 | /// This function uses the underlying single-precision implementation. 477 | /// \param arg function argument 478 | /// \return arc cosine value of \a arg 479 | half acos(half arg); 480 | 481 | /// Arc tangent function. 482 | /// This function uses the underlying single-precision implementation. 483 | /// \param arg function argument 484 | /// \return arc tangent value of \a arg 485 | half atan(half arg); 486 | 487 | /// Arc tangent function. 488 | /// This function uses the underlying single-precision implementation. 489 | /// \param x first argument 490 | /// \param y second argument 491 | /// \return arc tangent value 492 | half atan2(half x, half y); 493 | 494 | /// \} 495 | /// \name Hyperbolic functions 496 | /// \{ 497 | 498 | /// Hyperbolic sine. 499 | /// This function uses the underlying single-precision implementation. 500 | /// \param arg function argument 501 | /// \return hyperbolic sine value of \a arg 502 | half sinh(half arg); 503 | 504 | /// Hyperbolic cosine. 505 | /// This function uses the underlying single-precision implementation. 506 | /// \param arg function argument 507 | /// \return hyperbolic cosine value of \a arg 508 | half cosh(half arg); 509 | 510 | /// Hyperbolic tangent. 511 | /// This function uses the underlying single-precision implementation. 512 | /// \param arg function argument 513 | /// \return hyperbolic tangent value of \a arg 514 | half tanh(half arg); 515 | 516 | /// Hyperbolic area sine. 517 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 518 | /// \param arg function argument 519 | /// \return hyperbolic area sine value of \a arg 520 | half asinh(half arg); 521 | 522 | /// Hyperbolic area cosine. 523 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 524 | /// \param arg function argument 525 | /// \return hyperbolic area cosine value of \a arg 526 | half acosh(half arg); 527 | 528 | /// Hyperbolic area tangent. 529 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 530 | /// \param arg function argument 531 | /// \return hyperbolic area tangent value of \a arg 532 | half atanh(half arg); 533 | 534 | /// \} 535 | /// \name Error and gamma functions 536 | /// \{ 537 | 538 | /// Error function. 539 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 540 | /// \param arg function argument 541 | /// \return error function value of \a arg 542 | half erf(half arg); 543 | 544 | /// Complementary error function. 545 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 546 | /// \param arg function argument 547 | /// \return 1 minus error function value of \a arg 548 | half erfc(half arg); 549 | 550 | /// Natural logarithm of gamma function. 551 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 552 | /// \param arg function argument 553 | /// \return natural logarith of gamma function for \a arg 554 | half lgamma(half arg); 555 | 556 | /// Gamma function. 557 | /// This function uses the underlying single-precision implementation if C++11 `` functions are supported. 558 | /// \param arg function argument 559 | /// \return gamma function value of \a arg 560 | half tgamma(half arg); 561 | 562 | /// \} 563 | /// \name Rounding 564 | /// \{ 565 | 566 | /// Nearest integer not less than half value. 567 | /// \param arg half to round 568 | /// \return nearest integer not less than \a arg 569 | half ceil(half arg); 570 | 571 | /// Nearest integer not greater than half value. 572 | /// \param arg half to round 573 | /// \return nearest integer not greater than \a arg 574 | half floor(half arg); 575 | 576 | /// Nearest integer not greater in magnitude than half value. 577 | /// \param arg half to round 578 | /// \return nearest integer not greater in magnitude than \a arg 579 | half trunc(half arg); 580 | 581 | /// Nearest integer. 582 | /// \param arg half to round 583 | /// \return nearest integer, rounded away from zero in half-way cases 584 | half round(half arg); 585 | 586 | /// Nearest integer. 587 | /// \param arg half to round 588 | /// \return nearest integer, rounded away from zero in half-way cases 589 | long lround(half arg); 590 | 591 | /// Nearest integer. 592 | /// This function requires support for C++11 `long long`. 593 | /// \param arg half to round 594 | /// \return nearest integer, rounded away from zero in half-way cases 595 | long long llround(half arg); 596 | 597 | /// Nearest integer. 598 | /// \tparam E type of half expression 599 | /// \param arg half expression to round 600 | /// \return nearest integer using default rounding mode 601 | half nearbyint(half arg); 602 | 603 | /// Nearest integer. 604 | /// \tparam E type of half expression 605 | /// \param arg half expression to round 606 | /// \return nearest integer using default rounding mode 607 | half rint(half arg); 608 | 609 | /// Nearest integer. 610 | /// \tparam E type of half expression 611 | /// \param arg half expression to round 612 | /// \return nearest integer using default rounding mode 613 | long lrint(half arg); 614 | 615 | /// Nearest integer. 616 | /// This function requires support for C++11 `long long`. 617 | /// \tparam E type of half expression 618 | /// \param arg half expression to round 619 | /// \return nearest integer using default rounding mode 620 | long long llrint(half arg); 621 | 622 | /// \} 623 | /// \name Floating point manipulation 624 | /// \{ 625 | 626 | /// Decompress floating point number. 627 | /// \param arg number to decompress 628 | /// \param exp address to store exponent at 629 | /// \return significant in range [0.5, 1) 630 | half frexp(half arg, int *exp); 631 | 632 | /// Multiply by power of two. 633 | /// \param arg number to modify 634 | /// \param exp power of two to multiply with 635 | /// \return \a arg multplied by 2 raised to \a exp 636 | half ldexp(half arg, int exp); 637 | 638 | /// Extract integer and fractional parts. 639 | /// \param x number to decompress 640 | /// \param iptr address to store integer part at 641 | /// \return fractional part 642 | half modf(half x, half *iptr); 643 | 644 | /// Multiply by power of two. 645 | /// \param x number to modify 646 | /// \param exp power of two to multiply with 647 | /// \return \a arg multplied by 2 raised to \a exp 648 | half scalbn(half x, int exp); 649 | 650 | /// Multiply by power of two. 651 | /// \param x number to modify 652 | /// \param exp power of two to multiply with 653 | /// \return \a arg multplied by 2 raised to \a exp 654 | half scalbln(half x, long exp); 655 | 656 | /// Extract exponent. 657 | /// \param arg number to query 658 | /// \return floating point exponent 659 | /// \retval FP_ILOGB0 for zero 660 | /// \retval FP_ILOGBNAN for NaN 661 | /// \retval MAX_INT for infinity 662 | int ilogb(half arg); 663 | 664 | /// Extract exponent. 665 | /// \param arg number to query 666 | /// \return floating point exponent 667 | half logb(half arg); 668 | 669 | /// Next representable value. 670 | /// \param from value to compute next representable value for 671 | /// \param to direction towards which to compute next value 672 | /// \return next representable value after \a from in direction towards \a to 673 | half nextafter(half from, half to); 674 | 675 | /// Next representable value. 676 | /// \param from value to compute next representable value for 677 | /// \param to direction towards which to compute next value 678 | /// \return next representable value after \a from in direction towards \a to 679 | half nexttoward(half from, long double to); 680 | 681 | /// Take sign. 682 | /// \param x value to change sign for 683 | /// \param y value to take sign from 684 | /// \return value equal to \a x in magnitude and to \a y in sign 685 | half copysign(half x, half y); 686 | 687 | /// \} 688 | /// \name Floating point classification 689 | /// \{ 690 | 691 | /// Classify floating point value. 692 | /// \param arg number to classify 693 | /// \retval FP_ZERO for positive and negative zero 694 | /// \retval FP_SUBNORMAL for subnormal numbers 695 | /// \retval FP_INFINITY for positive and negative infinity 696 | /// \retval FP_NAN for NaNs 697 | /// \retval FP_NORMAL for all other (normal) values 698 | int fpclassify(half arg); 699 | 700 | /// Check if finite number. 701 | /// \param arg number to check 702 | /// \retval true if neither infinity nor NaN 703 | /// \retval false else 704 | bool isfinite(half arg); 705 | 706 | /// Check for infinity. 707 | /// \param arg number to check 708 | /// \retval true for positive or negative infinity 709 | /// \retval false else 710 | bool isinf(half arg); 711 | 712 | /// Check for NaN. 713 | /// \param arg number to check 714 | /// \retval true for NaNs 715 | /// \retval false else 716 | bool isnan(half arg); 717 | 718 | /// Check if normal number. 719 | /// \param arg number to check 720 | /// \retval true if normal number 721 | /// \retval false if either subnormal, zero, infinity or NaN 722 | bool isnormal(half arg); 723 | 724 | /// Check sign. 725 | /// \param arg number to check 726 | /// \retval true for negative number 727 | /// \retval false for positive number 728 | bool signbit(half arg); 729 | 730 | /// \} 731 | /// \name Comparison 732 | /// \{ 733 | 734 | /// Comparison for greater than. 735 | /// \param x first operand 736 | /// \param y second operand 737 | /// \retval true if \a x greater than \a y 738 | /// \retval false else 739 | bool isgreater(half x, half y); 740 | 741 | /// Comparison for greater equal. 742 | /// \param x first operand 743 | /// \param y second operand 744 | /// \retval true if \a x greater equal \a y 745 | /// \retval false else 746 | bool isgreaterequal(half x, half y); 747 | 748 | /// Comparison for less than. 749 | /// \param x first operand 750 | /// \param y second operand 751 | /// \retval true if \a x less than \a y 752 | /// \retval false else 753 | bool isless(half x, half y); 754 | 755 | /// Comparison for less equal. 756 | /// \param x first operand 757 | /// \param y second operand 758 | /// \retval true if \a x less equal \a y 759 | /// \retval false else 760 | bool islessequal(half x, half y); 761 | 762 | /// Comarison for less or greater. 763 | /// \param x first operand 764 | /// \param y second operand 765 | /// \retval true if either less or greater 766 | /// \retval false else 767 | bool islessgreater(half x, half y); 768 | 769 | /// Check if unordered. 770 | /// \param x first operand 771 | /// \param y second operand 772 | /// \retval true if unordered (one or two NaN operands) 773 | /// \retval false else 774 | bool isunordered(half x, half y); 775 | 776 | /// \} 777 | /// \name Casting 778 | /// \{ 779 | 780 | /// Cast to or from half-precision floating point number. 781 | /// This casts between [half](\ref half_float::half) and any built-in arithmetic type. The values are converted directly 782 | /// using the given rounding mode, without any roundtrip over `float` that a `static_cast` would otherwise do. It uses the 783 | /// default rounding mode. 784 | /// 785 | /// Using this cast with neither of the two types being a [half](\ref half_float::half) or with any of the two types 786 | /// not being a built-in arithmetic type (apart from [half](\ref half_float::half), of course) results in a compiler 787 | /// error and casting between [half](\ref half_float::half)s is just a no-op. 788 | /// \tparam T destination type (half or built-in arithmetic type) 789 | /// \tparam U source type (half or built-in arithmetic type) 790 | /// \param arg value to cast 791 | /// \return \a arg converted to destination type 792 | template T half_cast(const U &arg); 793 | 794 | /// Cast to or from half-precision floating point number. 795 | /// This casts between [half](\ref half_float::half) and any built-in arithmetic type. The values are converted directly 796 | /// using the given rounding mode, without any roundtrip over `float` that a `static_cast` would otherwise do. 797 | /// 798 | /// Using this cast with neither of the two types being a [half](\ref half_float::half) or with any of the two types 799 | /// not being a built-in arithmetic type (apart from [half](\ref half_float::half), of course) results in a compiler 800 | /// error and casting between [half](\ref half_float::half)s is just a no-op. 801 | /// \tparam T destination type (half or built-in arithmetic type) 802 | /// \tparam R rounding mode to use (see [std::float_round_style](http://en.cppreference.com/w/cpp/types/numeric_limits/float_round_style)) 803 | /// \tparam U source type (half or built-in arithmetic type) 804 | /// \param arg value to cast 805 | /// \return \a arg converted to destination type 806 | template T half_cast(const U &arg); 807 | /// \} 808 | 809 | 810 | /// Library-defined half-precision literals. 811 | /// Import this namespace to enable half-precision floating point literals (of course only if C++11 user-defined literals 812 | /// are supported and enabled): 813 | /// ~~~~{.cpp} 814 | /// using namespace half_float::literal; 815 | /// half_float::half = 4.2_h; 816 | /// ~~~~ 817 | namespace literal 818 | { 819 | /// Half literal. 820 | /// While this returns an actual half-precision value, half literals can unfortunately not be constant expressions due 821 | /// to rather involved conversions. 822 | /// \param value literal value 823 | /// \return half with given value (if representable) 824 | half operator""_h(long double value); 825 | } 826 | } 827 | 828 | 829 | /// Extensions to the C++ standard library. 830 | namespace std 831 | { 832 | /// Numeric limits for half-precision floats. 833 | /// Because of the underlying single-precision implementation of many operations, it inherits some properties from 834 | /// `std::numeric_limits`. 835 | /// 836 | /// **See also:** Documentation for [std::numeric_limits](http://en.cppreference.com/w/cpp/types/numeric_limits) 837 | template<> struct numeric_limits : public std::numeric_limits 838 | { 839 | /// Supports signed values. 840 | static constexpr bool is_signed = true; 841 | 842 | /// Is not exact. 843 | static constexpr bool is_exact = false; 844 | 845 | /// Doesn't provide modulo arithmetic. 846 | static constexpr bool is_modulo = false; 847 | 848 | /// IEEE conformant. 849 | static constexpr bool is_iec559 = true; 850 | 851 | /// Supports infinity. 852 | static constexpr bool has_infinity = true; 853 | 854 | /// Supports quiet NaNs. 855 | static constexpr bool has_quiet_NaN = true; 856 | 857 | /// Supports subnormal values. 858 | static constexpr std::float_denorm_style has_denorm = std::denorm_present; 859 | 860 | /// Rounding mode. 861 | /// Due to the mix of internal single-precision computations (using the rounding mode of the underlying 862 | /// single-precision implementation) with the rounding mode of the single-to-half conversions, the actual rounding 863 | /// mode might be `std::round_indeterminate` if the default half-precision rounding mode doesn't match the 864 | /// single-precision rounding mode. 865 | static constexpr std::float_round_style round_style = /* unspecified */; 866 | 867 | /// Significant digits. 868 | static constexpr int digits = 11; 869 | 870 | /// Significant decimal digits. 871 | static constexpr int digits10 = 3; 872 | 873 | /// Required decimal digits to represent all possible values. 874 | static constexpr int max_digits10 = 5; 875 | 876 | /// Number base. 877 | static constexpr int radix = 2; 878 | 879 | /// One more than smallest exponent. 880 | static constexpr int min_exponent = -13; 881 | 882 | /// Smallest normalized representable power of 10. 883 | static constexpr int min_exponent10 = -4; 884 | 885 | /// One more than largest exponent 886 | static constexpr int max_exponent = 16; 887 | 888 | /// Largest finitely representable power of 10. 889 | static constexpr int max_exponent10 = 4; 890 | 891 | /// Smallest positive normal value. 892 | static constexpr half_float::half min() noexcept; 893 | 894 | /// Smallest finite value. 895 | static constexpr half_float::half lowest() noexcept; 896 | 897 | /// Largest finite value. 898 | static constexpr half_float::half max() noexcept; 899 | 900 | /// Difference between one and next representable value. 901 | static constexpr half_float::half epsilon() noexcept; 902 | 903 | /// Maximum rounding error. 904 | static constexpr half_float::half round_error() noexcept; 905 | 906 | /// Positive infinity. 907 | static constexpr half_float::half infinity() noexcept; 908 | 909 | /// Quiet NaN. 910 | static constexpr half_float::half quiet_NaN() noexcept; 911 | 912 | /// Signalling NaN. 913 | static constexpr half_float::half signaling_NaN() noexcept; 914 | 915 | /// Smallest positive subnormal value. 916 | static constexpr half_float::half denorm_min() noexcept; 917 | }; 918 | 919 | /// Hash function for half-precision floats. 920 | /// This is only defined if C++11 `std::hash` is supported and enabled. 921 | /// 922 | /// **See also:** Documentation for [std::hash](http://en.cppreference.com/w/cpp/utility/hash) 923 | template<> struct hash 924 | { 925 | /// Type of function argument. 926 | typedef half_float::half argument_type; 927 | 928 | /// Function return type. 929 | typedef std::size_t result_type; 930 | 931 | /// Compute hash function. 932 | /// \param arg half to hash 933 | /// \return hash value 934 | std::size_t operator()(half_float::half arg) const; 935 | }; 936 | } 937 | -------------------------------------------------------------------------------- /web/layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /web/web.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {B36DE2E9-6E9C-4629-AEDA-8EFAE78E29D0} 15 | Win32Proj 16 | web 17 | 18 | 19 | 20 | Utility 21 | true 22 | Unicode 23 | v140 24 | 25 | 26 | Utility 27 | false 28 | true 29 | Unicode 30 | v140 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | $(ProjectDir) 45 | 46 | 47 | false 48 | $(ProjectDir) 49 | 50 | 51 | 52 | 53 | 54 | Level3 55 | Disabled 56 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 57 | 58 | 59 | Console 60 | true 61 | 62 | 63 | 64 | 65 | Level3 66 | 67 | 68 | MaxSpeed 69 | true 70 | true 71 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 72 | 73 | 74 | Console 75 | true 76 | true 77 | true 78 | 79 | 80 | 81 | 82 | Document 83 | "C:\Program Files\doxygen\bin\doxygen.exe" $(InputPath) 84 | Generating Documentation 85 | html 86 | $(ProjectDir)layout.xml;$(ProjectDir)half.hpp;$(ProjectDir)Mainpage.md;$(ProjectDir)News.md;$(ProjectDir)../ChangeLog.txt 87 | $(ProjectDir)layout.xml;$(ProjectDir)half.hpp;$(ProjectDir)Mainpage.md;$(ProjectDir)News.md;$(ProjectDir)../ChangeLog.txt 88 | html 89 | Generating Documentation 90 | "C:\Program Files\doxygen\bin\doxygen.exe" $(InputPath) 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /web/web.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 6 | h;hpp;hxx;hm;inl;inc;xsd 7 | 8 | 9 | {e31a1aed-8ae0-4fb3-8b17-812dc67ff73e} 10 | md;txt 11 | 12 | 13 | 14 | 15 | Dokumentationsdateien 16 | 17 | 18 | Dokumentationsdateien 19 | 20 | 21 | 22 | 23 | Headerdateien 24 | 25 | 26 | 27 | 28 | 29 | --------------------------------------------------------------------------------