diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/serfloat.cpp | 64 | ||||
-rw-r--r-- | src/util/serfloat.h | 16 | ||||
-rw-r--r-- | src/util/time.cpp | 2 | ||||
-rw-r--r-- | src/util/time.h | 4 |
4 files changed, 83 insertions, 3 deletions
diff --git a/src/util/serfloat.cpp b/src/util/serfloat.cpp new file mode 100644 index 0000000000..8edca924cd --- /dev/null +++ b/src/util/serfloat.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <util/serfloat.h> + +#include <cmath> +#include <limits> + +double DecodeDouble(uint64_t v) noexcept { + static constexpr double NANVAL = std::numeric_limits<double>::quiet_NaN(); + static constexpr double INFVAL = std::numeric_limits<double>::infinity(); + double sign = 1.0; + if (v & 0x8000000000000000) { + sign = -1.0; + v ^= 0x8000000000000000; + } + // Zero + if (v == 0) return copysign(0.0, sign); + // Infinity + if (v == 0x7ff0000000000000) return copysign(INFVAL, sign); + // Other numbers + int exp = (v & 0x7FF0000000000000) >> 52; + uint64_t man = v & 0xFFFFFFFFFFFFF; + if (exp == 2047) { + // NaN + return NANVAL; + } else if (exp == 0) { + // Subnormal + return copysign(ldexp((double)man, -1074), sign); + } else { + // Normal + return copysign(ldexp((double)(man + 0x10000000000000), -1075 + exp), sign); + } +} + +uint64_t EncodeDouble(double f) noexcept { + int cls = std::fpclassify(f); + uint64_t sign = 0; + if (copysign(1.0, f) == -1.0) { + f = -f; + sign = 0x8000000000000000; + } + // Zero + if (cls == FP_ZERO) return sign; + // Infinity + if (cls == FP_INFINITE) return sign | 0x7ff0000000000000; + // NaN + if (cls == FP_NAN) return 0x7ff8000000000000; + // Other numbers + int exp; + uint64_t man = std::round(std::frexp(f, &exp) * 9007199254740992.0); + if (exp < -1021) { + // Too small to represent, encode 0 + if (exp < -1084) return sign; + // Subnormal numbers + return sign | (man >> (-1021 - exp)); + } else { + // Too big to represent, encode infinity + if (exp > 1024) return sign | 0x7ff0000000000000; + // Normal numbers + return sign | (((uint64_t)(1022 + exp)) << 52) | (man & 0xFFFFFFFFFFFFF); + } +} diff --git a/src/util/serfloat.h b/src/util/serfloat.h new file mode 100644 index 0000000000..4d912b0176 --- /dev/null +++ b/src/util/serfloat.h @@ -0,0 +1,16 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_SERFLOAT_H +#define BITCOIN_UTIL_SERFLOAT_H + +#include <stdint.h> + +/* Encode a double using the IEEE 754 binary64 format. All NaNs are encoded as x86/ARM's + * positive quiet NaN with payload 0. */ +uint64_t EncodeDouble(double f) noexcept; +/* Reverse operation of DecodeDouble. DecodeDouble(EncodeDouble(f))==f unless isnan(f). */ +double DecodeDouble(uint64_t v) noexcept; + +#endif // BITCOIN_UTIL_SERFLOAT_H diff --git a/src/util/time.cpp b/src/util/time.cpp index e6f0986a39..eda710b12c 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -124,7 +124,7 @@ int64_t GetTimeMicros() return int64_t{GetSystemTime<std::chrono::microseconds>().count()}; } -int64_t GetSystemTimeInSeconds() +int64_t GetTimeSeconds() { return int64_t{GetSystemTime<std::chrono::seconds>().count()}; } diff --git a/src/util/time.h b/src/util/time.h index 7ebcaaa339..4aee01967d 100644 --- a/src/util/time.h +++ b/src/util/time.h @@ -39,7 +39,7 @@ inline double CountSecondsDouble(SecondsDouble t) { return t.count(); } /** * DEPRECATED - * Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable) + * Use either GetTimeSeconds (not mockable) or GetTime<T> (mockable) */ int64_t GetTime(); @@ -48,7 +48,7 @@ int64_t GetTimeMillis(); /** Returns the system time (not mockable) */ int64_t GetTimeMicros(); /** Returns the system time (not mockable) */ -int64_t GetSystemTimeInSeconds(); // Like GetTime(), but not mockable +int64_t GetTimeSeconds(); // Like GetTime(), but not mockable /** * DEPRECATED |