/Users/eugenesiegel/btc/bitcoin/src/util/serfloat.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | static constexpr double NANVAL = std::numeric_limits<double>::quiet_NaN(); |
12 | 0 | 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 | 0 | } else { |
32 | | // Normal |
33 | 0 | return copysign(ldexp((double)(man + 0x10000000000000), -1075 + exp), sign); |
34 | 0 | } |
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 | 0 | 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 | 0 | } 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 | 0 | } |
64 | 0 | } |