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