Line data Source code
1 : /** 2 : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org> 3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev> 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 : **/ 23 : 24 : #ifndef STAPPLER_CORE_UTILS_SPHALFFLOAT_H_ 25 : #define STAPPLER_CORE_UTILS_SPHALFFLOAT_H_ 26 : 27 : #include "SPCore.h" 28 : 29 : namespace STAPPLER_VERSIONIZED stappler::halffloat { 30 : 31 : // see https://en.wikipedia.org/wiki/Half_precision_floating-point_format 32 : 33 25 : constexpr uint16_t nan() { return (uint16_t)0x7e00; } 34 25 : constexpr uint16_t posinf() { return (uint16_t)(31 << 10); } 35 25 : constexpr uint16_t neginf() { return (uint16_t)(63 << 10); } 36 : 37 3769597 : inline constexpr float decode(uint16_t half) { 38 3769597 : uint16_t exp = (half >> 10) & 0x1f; 39 3769597 : uint16_t mant = half & 0x3ff; 40 7538818 : double val = (exp == 0) ? std::ldexp(mant, -24) 41 3769372 : : ((exp != 31) ? std::ldexp(mant + 1024, exp - 25) 42 150 : : (mant == 0 ? NumericLimits<float>::infinity() : stappler::nan())); 43 : 44 3769596 : return (half & 0x8000) ? -val : val; 45 : } 46 : 47 52689 : inline constexpr uint16_t encode(float val) { 48 : union { 49 : float f; 50 : uint32_t i; 51 52689 : } u32 = { val }; 52 : 53 52689 : uint16_t bits = (u32.i >> 16) & 0x8000; /* Get the sign */ 54 52689 : uint16_t m = (u32.i >> 12) & 0x07ff; /* Keep one extra bit for rounding */ 55 52689 : uint32_t e = (u32.i >> 23) & 0xff; /* Using int is faster here */ 56 : 57 : /* If zero, or denormal, or exponent underflows too much for a denormal 58 : * half, return signed zero. */ 59 52689 : if (e < 103) { 60 25 : return bits; 61 : } 62 : 63 : /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */ 64 52664 : if (e > 142) { 65 75 : bits |= 0x7c00u; 66 : /* If exponent was 0xff and one mantissa bit was set, it means NaN, 67 : * not Inf, so make sure we set one mantissa bit too. */ 68 75 : bits |= (e == 255) && (u32.i & 0x007fffffu); 69 75 : return bits; 70 : } 71 : 72 : /* If exponent underflows but not too much, return a denormal */ 73 52589 : if (e < 113) { 74 0 : m |= 0x0800u; 75 : /* Extra rounding may overflow and set mantissa to 0 and exponent 76 : * to 1, which is OK. */ 77 0 : bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1); 78 0 : return bits; 79 : } 80 : 81 52589 : bits |= ((e - 112) << 10) | (m >> 1); 82 : /* Extra rounding. An overflow will set mantissa to 0 and increment 83 : * the exponent, which is OK. */ 84 52589 : bits += m & 1; 85 52589 : return bits; 86 : } 87 : 88 : } 89 : 90 : #endif /* STAPPLER_CORE_UTILS_SPHALFFLOAT_H_ */