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 : 0 : 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 : 0 : double sign = 1.0; 14 [ # # ]: 0 : if (v & 0x8000000000000000) { 15 : 0 : sign = -1.0; 16 : 0 : v ^= 0x8000000000000000; 17 : 0 : } 18 : : // Zero 19 [ # # ]: 0 : if (v == 0) return copysign(0.0, sign); 20 : : // Infinity 21 [ # # ]: 0 : if (v == 0x7ff0000000000000) return copysign(INFVAL, sign); 22 : : // Other numbers 23 : 0 : int exp = (v & 0x7FF0000000000000) >> 52; 24 : 0 : uint64_t man = v & 0xFFFFFFFFFFFFF; 25 [ # # ]: 0 : if (exp == 2047) { 26 : : // NaN 27 : 0 : return NANVAL; 28 [ # # ]: 0 : } else if (exp == 0) { 29 : : // Subnormal 30 : 0 : return copysign(ldexp((double)man, -1074), sign); 31 : : } else { 32 : : // Normal 33 : 0 : return copysign(ldexp((double)(man + 0x10000000000000), -1075 + exp), sign); 34 : : } 35 : 0 : } 36 : : 37 : 0 : uint64_t EncodeDouble(double f) noexcept { 38 [ # # ]: 0 : int cls = std::fpclassify(f); 39 : 0 : uint64_t sign = 0; 40 [ # # ]: 0 : if (copysign(1.0, f) == -1.0) { 41 : 0 : f = -f; 42 : 0 : sign = 0x8000000000000000; 43 : 0 : } 44 : : // Zero 45 [ # # ]: 0 : if (cls == FP_ZERO) return sign; 46 : : // Infinity 47 [ # # ]: 0 : if (cls == FP_INFINITE) return sign | 0x7ff0000000000000; 48 : : // NaN 49 [ # # ]: 0 : if (cls == FP_NAN) return 0x7ff8000000000000; 50 : : // Other numbers 51 : : int exp; 52 : 0 : uint64_t man = std::round(std::frexp(f, &exp) * 9007199254740992.0); 53 [ # # ]: 0 : if (exp < -1021) { 54 : : // Too small to represent, encode 0 55 [ # # ]: 0 : if (exp < -1084) return sign; 56 : : // Subnormal numbers 57 : 0 : return sign | (man >> (-1021 - exp)); 58 : : } else { 59 : : // Too big to represent, encode infinity 60 [ # # ]: 0 : if (exp > 1024) return sign | 0x7ff0000000000000; 61 : : // Normal numbers 62 : 0 : return sign | (((uint64_t)(1022 + exp)) << 52) | (man & 0xFFFFFFFFFFFFF); 63 : : } 64 : 0 : }