mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 18:49:30 +01:00
Add platform-independent float encoder/decoder
This commit is contained in:
parent
e40224d0c7
commit
2be4cd94f4
@ -253,6 +253,7 @@ BITCOIN_CORE_H = \
|
||||
util/moneystr.h \
|
||||
util/rbf.h \
|
||||
util/readwritefile.h \
|
||||
util/serfloat.h \
|
||||
util/settings.h \
|
||||
util/sock.h \
|
||||
util/spanparsing.h \
|
||||
@ -595,6 +596,7 @@ libbitcoin_util_a_SOURCES = \
|
||||
util/settings.cpp \
|
||||
util/thread.cpp \
|
||||
util/threadnames.cpp \
|
||||
util/serfloat.cpp \
|
||||
util/spanparsing.cpp \
|
||||
util/strencodings.cpp \
|
||||
util/string.cpp \
|
||||
|
64
src/util/serfloat.cpp
Normal file
64
src/util/serfloat.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
16
src/util/serfloat.h
Normal file
16
src/util/serfloat.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user