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