Branch data Line data Source code
1 : : // Copyright (c) 2021 The Bitcoin Core developers 2 : : // Distributed under the MIT software license, see the accompanying 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : : 5 : : #include <util/serfloat.h> 6 : : 7 : : #include <cmath> 8 : : #include <limits> 9 : : 10 : 1123554 : double DecodeDouble(uint64_t v) noexcept { 11 : : static constexpr double NANVAL = std::numeric_limits<double>::quiet_NaN(); 12 : : static constexpr double INFVAL = std::numeric_limits<double>::infinity(); 13 : 1123554 : double sign = 1.0; 14 [ + + ]: 1123554 : if (v & 0x8000000000000000) { 15 : 36174 : sign = -1.0; 16 : 36174 : v ^= 0x8000000000000000; 17 : 36174 : } 18 : : // Zero 19 [ + + ]: 1123554 : if (v == 0) return copysign(0.0, sign); 20 : : // Infinity 21 [ + + ]: 876876 : if (v == 0x7ff0000000000000) return copysign(INFVAL, sign); 22 : : // Other numbers 23 : 876606 : int exp = (v & 0x7FF0000000000000) >> 52; 24 : 876606 : uint64_t man = v & 0xFFFFFFFFFFFFF; 25 [ + + ]: 876606 : if (exp == 2047) { 26 : : // NaN 27 : 3581 : return NANVAL; 28 [ + + ]: 873025 : } else if (exp == 0) { 29 : : // Subnormal 30 : 13658 : return copysign(ldexp((double)man, -1074), sign); 31 : : } else { 32 : : // Normal 33 : 859367 : return copysign(ldexp((double)(man + 0x10000000000000), -1075 + exp), sign); 34 : : } 35 : 1123554 : } 36 : : 37 : 205133 : uint64_t EncodeDouble(double f) noexcept { 38 [ + - ]: 205133 : int cls = std::fpclassify(f); 39 : 205133 : uint64_t sign = 0; 40 [ + + ]: 205133 : if (copysign(1.0, f) == -1.0) { 41 : 132 : f = -f; 42 : 132 : sign = 0x8000000000000000; 43 : 132 : } 44 : : // Zero 45 [ + + ]: 205133 : if (cls == FP_ZERO) return sign; 46 : : // Infinity 47 [ + + ]: 14411 : if (cls == FP_INFINITE) return sign | 0x7ff0000000000000; 48 : : // NaN 49 [ + + ]: 14379 : if (cls == FP_NAN) return 0x7ff8000000000000; 50 : : // Other numbers 51 : : int exp; 52 : 14289 : uint64_t man = std::round(std::frexp(f, &exp) * 9007199254740992.0); 53 [ + + ]: 14289 : if (exp < -1021) { 54 : : // Too small to represent, encode 0 55 [ - + ]: 114 : if (exp < -1084) return sign; 56 : : // Subnormal numbers 57 : 114 : return sign | (man >> (-1021 - exp)); 58 : : } else { 59 : : // Too big to represent, encode infinity 60 [ - + ]: 14175 : if (exp > 1024) return sign | 0x7ff0000000000000; 61 : : // Normal numbers 62 : 14175 : return sign | (((uint64_t)(1022 + exp)) << 52) | (man & 0xFFFFFFFFFFFFF); 63 : : } 64 : 205133 : }