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 : }