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