New floats format, STAmount compatible (#6600)

This commit is contained in:
Olek
2026-04-07 20:19:19 -04:00
committed by GitHub
parent 75f66bd9fe
commit d2641d85bd
19 changed files with 2566 additions and 562 deletions

View File

@@ -249,6 +249,7 @@ words:
- STATSDCOLLECTOR
- stissue
- stnum
- stnumber
- stobj
- stobject
- stpath

View File

@@ -381,6 +381,9 @@ public:
friend Number
root2(Number f);
friend Number
log10(Number const&, int);
// Thread local rounding control. Default is to_nearest
enum rounding_mode { to_nearest, towards_zero, downward, upward };
static rounding_mode

View File

@@ -37,6 +37,8 @@ enum class HostFunctionError : int32_t {
OUT_OF_GAS = -22,
};
using FloatPair = std::pair<int64_t, int32_t>;
inline int32_t
HfErrorToInt(HostFunctionError e)
{
@@ -54,6 +56,24 @@ floatFromIntImpl(int64_t x, int32_t mode);
Expected<Bytes, HostFunctionError>
floatFromUintImpl(uint64_t x, int32_t mode);
Expected<Bytes, HostFunctionError>
floatFromSTAmountImpl(STAmount const& x, int32_t mode);
Expected<Bytes, HostFunctionError>
floatFromSTNumberImpl(STNumber const& x, int32_t mode);
Expected<int64_t, HostFunctionError>
floatToIntImpl(Slice const& x, int32_t mode);
Expected<FloatPair, HostFunctionError>
floatToMantissaAndExponentImpl(Slice const& x);
Expected<Bytes, HostFunctionError>
floatNegateImpl(Slice const& x);
Expected<Bytes, HostFunctionError>
floatAbsImpl(Slice const& x);
Expected<Bytes, HostFunctionError>
floatSetImpl(int64_t mantissa, int32_t exponent, int32_t mode);
@@ -440,6 +460,42 @@ struct HostFunctions
return Unexpected(HostFunctionError::INTERNAL);
}
virtual Expected<Bytes, HostFunctionError>
floatFromSTAmount(STAmount const& x, int32_t mode) const
{
return Unexpected(HostFunctionError::INTERNAL);
}
virtual Expected<Bytes, HostFunctionError>
floatFromSTNumber(STNumber const& x, int32_t mode) const
{
return Unexpected(HostFunctionError::INTERNAL);
}
virtual Expected<int64_t, HostFunctionError>
floatToInt(Slice const& x, int32_t mode) const
{
return Unexpected(HostFunctionError::INTERNAL);
}
virtual Expected<FloatPair, HostFunctionError>
floatToMantissaAndExponent(Slice const& x) const
{
return Unexpected(HostFunctionError::INTERNAL);
}
virtual Expected<Bytes, HostFunctionError>
floatNegate(Slice const& x) const
{
return Unexpected(HostFunctionError::INTERNAL);
}
virtual Expected<Bytes, HostFunctionError>
floatAbs(Slice const& x) const
{
return Unexpected(HostFunctionError::INTERNAL);
}
virtual Expected<Bytes, HostFunctionError>
floatSet(int64_t mantissa, int32_t exponent, int32_t mode) const
{

View File

@@ -254,6 +254,24 @@ public:
Expected<Bytes, HostFunctionError>
floatFromUint(uint64_t x, int32_t mode) const override;
Expected<Bytes, HostFunctionError>
floatFromSTAmount(STAmount const& x, int32_t mode) const override;
Expected<Bytes, HostFunctionError>
floatFromSTNumber(STNumber const& x, int32_t mode) const override;
Expected<int64_t, HostFunctionError>
floatToInt(Slice const& x, int32_t mode) const override;
Expected<FloatPair, HostFunctionError>
floatToMantissaAndExponent(Slice const& x) const override;
Expected<Bytes, HostFunctionError>
floatNegate(Slice const& x) const override;
Expected<Bytes, HostFunctionError>
floatAbs(Slice const& x) const override;
Expected<Bytes, HostFunctionError>
floatSet(int64_t mantissa, int32_t exponent, int32_t mode) const override;
@@ -282,14 +300,4 @@ public:
floatLog(Slice const& x, int32_t mode) const override;
};
namespace wasm_float {
// The range for the mantissa and exponent when normalized
static std::int64_t constexpr wasmMinMantissa = 1'000'000'000'000'000ll;
static std::int64_t constexpr wasmMaxMantissa = wasmMinMantissa * 10 - 1;
static int constexpr wasmMinExponent = -96;
static int constexpr wasmMaxExponent = 80;
} // namespace wasm_float
} // namespace xrpl

View File

@@ -260,6 +260,31 @@ using floatFromUint_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t,
wasm_trap_t*
floatFromUint_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
using floatFromSTAmount_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t*
floatFromSTAmount_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
using floatFromSTNumber_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t*
floatFromSTNumber_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
using floatToInt_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t*
floatToInt_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
using floatToMantissaAndExponent_proto =
int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, uint8_t*, int32_t);
wasm_trap_t*
floatToMantissaAndExponent_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
using floatNegate_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t*
floatNegate_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
using floatAbs_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t*
floatAbs_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
using floatSet_proto = int32_t(int32_t, int64_t, uint8_t*, int32_t, int32_t);
wasm_trap_t*
floatSet_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);

View File

@@ -949,10 +949,10 @@ power(Number const& f, unsigned n)
static Number
ln(Number const& x, int iterations = 50)
{
static Number const N0(0);
static Number const N2(2, 0);
static Number const N05(5, -1);
static Number const LN2(693'147'180'559'945'309ll, -18);
Number const N0(0);
Number const N2(2, 0);
Number const N05(5, -1);
Number const LN2(693'147'180'559'945'309ll, -18);
if (x <= 0)
{
@@ -993,8 +993,8 @@ ln(Number const& x, int iterations = 50)
Number
log10(Number const& x, int iterations)
{
static Number const N0(0);
static Number const LN10(2'302'585'092'994'046ll, -15);
Number const N0(0);
Number const LN10(2'302'585'092'994'045'684ll, -18);
if (x <= 0)
{
@@ -1012,8 +1012,9 @@ log10(Number const& x, int iterations)
}
// (1 <= normalX < 10)
// x = normalX * 10^norm
// ln(x) = ln(normalX * 10^norm) = ln(normalX) + norm * ln(10)
int const diffExp = 15 + x.exponent();
int const diffExp = Number::mantissaLog() + x.exponent_;
Number const normalX = x / Number(1, diffExp);
auto const lnX = ln(normalX, iterations) + diffExp * LN10;
auto const lgX = lnX / LN10;

View File

@@ -1,4 +1,6 @@
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STBitString.h>
#include <xrpl/protocol/STNumber.h>
#include <xrpl/protocol/digest.h>
#include <xrpl/tx/wasm/HostFuncImpl.h>
@@ -12,137 +14,78 @@ namespace wasm_float {
namespace detail {
class Number2 : public Number
class WasmNumber : public Number
{
protected:
static Bytes const floatNull;
static unsigned constexpr encodedFloatSize = 8;
static int32_t constexpr encodedMantissaBits = 54;
static int32_t constexpr encodedExponentBits = 8;
static_assert(wasmMinExponent < 0);
static uint64_t constexpr maxEncodedMantissa = (1ull << (encodedMantissaBits + 1)) - 1;
bool good_;
static unsigned constexpr encodedFloatSize = 12;
bool good_ = false;
public:
Number2(Slice const& data) : good_(false)
WasmNumber(Slice const& data)
{
if (data.size() != encodedFloatSize)
return;
if (std::ranges::equal(floatNull, data))
try
{
SerialIter it(data);
Number const x = STNumber(it, sfNumber).value();
*static_cast<Number*>(this) = x;
}
catch (...)
{
good_ = true;
return;
}
uint64_t const v = SerialIter(data).get64();
if ((v & STAmount::cIssuedCurrency) == 0u)
return;
int32_t const e = static_cast<int32_t>((v >> encodedMantissaBits) & 0xFFull);
int32_t const decodedExponent = e + wasmMinExponent - 1; // e - 97
if (decodedExponent < wasmMinExponent || decodedExponent > wasmMaxExponent)
return;
int64_t const neg = ((v & STAmount::cPositive) != 0u) ? 1 : -1;
int64_t const m = neg * static_cast<int64_t>(v & ((1ull << encodedMantissaBits) - 1));
if (m == 0)
return;
Number const x(makeNumber(m, decodedExponent));
if (m != x.mantissa() || decodedExponent != x.exponent())
return; // not canonical
*static_cast<Number*>(this) = x;
good_ = true;
}
WasmNumber(Number const& n) : WasmNumber(n.mantissa(), n.exponent()) // ensure Number canonized
{
}
template <class T>
Number2(T mantissa = 0, int32_t exponent = 0) : Number(), good_(false)
WasmNumber(T mantissa = 0, int32_t exponent = 0)
{
if (!mantissa)
try
{
Number n;
if constexpr (std::is_signed_v<T>)
{
n = Number(static_cast<int64_t>(mantissa), exponent);
}
else
{
n = Number(static_cast<uint64_t>(mantissa), exponent, Number::normalized());
}
*static_cast<Number*>(this) = n;
}
catch (...)
{
good_ = true;
return;
}
auto const n = makeNumber(mantissa, exponent);
auto const e = n.exponent();
if (e < wasmMinExponent)
{
good_ = true; // value is zero(as in Numbers behavior)
return;
}
if (e > wasmMaxExponent)
return;
*static_cast<Number*>(this) = n;
good_ = true;
}
Number2(Number const& n) : Number2(n.mantissa(), n.exponent()) // ensure Number canonized
{
}
static Number
makeNumber(int64_t mantissa, int32_t exponent)
{
if (mantissa < 0)
return Number(true, -static_cast<uint64_t>(mantissa), exponent, Number::normalized());
return Number(false, mantissa, exponent, Number::normalized());
}
static Number
makeNumber(uint64_t mantissa, int32_t exponent)
{
return Number(false, mantissa, exponent, Number::normalized());
}
WasmNumber&
operator=(WasmNumber const&) = default;
explicit
operator bool() const
{
return good_;
}
explicit
operator int64_t() const
{
return Number::operator int64_t();
}
Expected<Bytes, HostFunctionError>
toBytes() const
{
if (!good_)
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
auto const m = mantissa();
auto const e = exponent();
uint64_t v = m >= 0 ? STAmount::cPositive : 0;
v |= STAmount::cIssuedCurrency;
uint64_t const absM = std::abs(m);
if (absM == 0u)
{
return floatNull;
}
if (absM > maxEncodedMantissa)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR); // LCOV_EXCL_LINE
}
v |= absM;
if (e > wasmMaxExponent)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
if (e < wasmMinExponent)
{
return floatNull;
}
uint64_t const normExp = e - wasmMinExponent + 1; //+97
v |= normExp << encodedMantissaBits;
Serializer msg;
msg.add64(v);
STNumber(sfNumber, *this).add(msg);
auto data = msg.getData();
#ifdef DEBUG_OUTPUT
@@ -153,33 +96,26 @@ public:
std::cout << std::setw(2) << (unsigned)c << " ";
std::cout << std::dec << std::setfill(' ') << std::endl;
#endif
return data;
}
};
Bytes const Number2::floatNull = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
struct FloatState
{
Number::rounding_mode oldMode_;
MantissaRange::mantissa_scale oldScale_;
bool good_{false};
bool good_ = false;
FloatState(int32_t mode) : oldMode_(Number::getround()), oldScale_(Number::getMantissaScale())
FloatState(int32_t mode) : oldMode_(Number::getround())
{
if (mode < Number::rounding_mode::to_nearest || mode > Number::rounding_mode::upward)
return;
Number::setround(static_cast<Number::rounding_mode>(mode));
Number::setMantissaScale(MantissaRange::mantissa_scale::small);
good_ = true;
}
~FloatState()
{
Number::setround(oldMode_);
Number::setMantissaScale(oldScale_);
}
operator bool() const
@@ -195,7 +131,7 @@ floatToString(Slice const& data)
{
// set default mode as we don't expect it will be used here
detail::FloatState const rm(Number::rounding_mode::to_nearest);
detail::Number2 const num(data);
detail::WasmNumber const num(data);
if (!num)
{
std::string hex;
@@ -203,7 +139,6 @@ floatToString(Slice const& data)
boost::algorithm::hex(data.begin(), data.end(), std::back_inserter(hex));
return "Invalid data: " + hex;
}
auto const s = to_string(num);
return s;
}
@@ -217,15 +152,17 @@ floatFromIntImpl(int64_t x, int32_t mode)
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const num(x);
return num.toBytes();
detail::WasmNumber const num(x);
if (!num)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED); // LCOV_EXCL_LINE
auto const r = num.toBytes();
return r;
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
// LCOV_EXCL_STOP
}
@@ -238,8 +175,10 @@ floatFromUintImpl(uint64_t x, int32_t mode)
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const num(x);
auto r = num.toBytes();
detail::WasmNumber const num(x);
if (!num)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED); // LCOV_EXCL_LINE
auto const r = num.toBytes();
return r;
}
// LCOV_EXCL_START
@@ -247,7 +186,146 @@ floatFromUintImpl(uint64_t x, int32_t mode)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatFromSTAmountImpl(STAmount const& x, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::WasmNumber const num(static_cast<Number>(x));
if (!num)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED); // LCOV_EXCL_LINE
auto const r = num.toBytes();
return r;
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatFromSTNumberImpl(STNumber const& x, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::WasmNumber const num(x.value());
if (!num)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED); // LCOV_EXCL_LINE
auto const r = num.toBytes();
return r;
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
// LCOV_EXCL_STOP
}
Expected<int64_t, HostFunctionError>
floatToIntImpl(Slice const& x, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::WasmNumber const num(x);
if (!num)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED); // LCOV_EXCL_LINE
int64_t const r(num);
return r;
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
// LCOV_EXCL_STOP
}
Expected<FloatPair, HostFunctionError>
floatToMantissaAndExponentImpl(Slice const& x)
{
try
{
detail::FloatState const rm(Number::rounding_mode::to_nearest);
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::WasmNumber const num(x);
if (!num)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED); // LCOV_EXCL_LINE
return FloatPair(num.mantissa(), num.exponent());
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatNegateImpl(Slice const& x)
{
try
{
detail::FloatState const rm(Number::rounding_mode::to_nearest);
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::WasmNumber const num(x);
if (!num)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::WasmNumber const res = -num;
return res.toBytes();
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatAbsImpl(Slice const& x)
{
try
{
detail::FloatState const rm(Number::rounding_mode::to_nearest);
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::WasmNumber const num(x);
if (!num)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::WasmNumber const res = abs(num);
return res.toBytes();
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
// LCOV_EXCL_STOP
}
@@ -259,16 +337,15 @@ floatSetImpl(int64_t mantissa, int32_t exponent, int32_t mode)
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const num(mantissa, exponent);
detail::WasmNumber const num(mantissa, exponent);
if (!num)
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
return num.toBytes();
}
catch (...)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
Expected<int32_t, HostFunctionError>
@@ -278,10 +355,11 @@ floatCompareImpl(Slice const& x, Slice const& y)
{
// set default mode as we don't expect it will be used here
detail::FloatState const rm(Number::rounding_mode::to_nearest);
detail::Number2 const xx(x);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const yy(y);
detail::WasmNumber const yy(y);
if (!yy)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
if (xx < yy)
@@ -295,7 +373,6 @@ floatCompareImpl(Slice const& x, Slice const& y)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
// LCOV_EXCL_STOP
}
@@ -308,13 +385,13 @@ floatAddImpl(Slice const& x, Slice const& y, int32_t mode)
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const xx(x);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const yy(y);
detail::WasmNumber const yy(y);
if (!yy)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const res = xx + yy;
detail::WasmNumber const res = xx + yy;
return res.toBytes();
}
@@ -323,7 +400,6 @@ floatAddImpl(Slice const& x, Slice const& y, int32_t mode)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
// LCOV_EXCL_STOP
}
@@ -335,13 +411,13 @@ floatSubtractImpl(Slice const& x, Slice const& y, int32_t mode)
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const xx(x);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const yy(y);
detail::WasmNumber const yy(y);
if (!yy)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const res = xx - yy;
detail::WasmNumber const res = xx - yy;
return res.toBytes();
}
@@ -350,7 +426,6 @@ floatSubtractImpl(Slice const& x, Slice const& y, int32_t mode)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
// LCOV_EXCL_STOP
}
@@ -362,13 +437,13 @@ floatMultiplyImpl(Slice const& x, Slice const& y, int32_t mode)
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const xx(x);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const yy(y);
detail::WasmNumber const yy(y);
if (!yy)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const res = xx * yy;
detail::WasmNumber const res = xx * yy;
return res.toBytes();
}
@@ -377,7 +452,6 @@ floatMultiplyImpl(Slice const& x, Slice const& y, int32_t mode)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
// LCOV_EXCL_STOP
}
@@ -389,13 +463,13 @@ floatDivideImpl(Slice const& x, Slice const& y, int32_t mode)
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const xx(x);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const yy(y);
detail::WasmNumber const yy(y);
if (!yy)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const res = xx / yy;
detail::WasmNumber const res = xx / yy;
return res.toBytes();
}
@@ -403,7 +477,6 @@ floatDivideImpl(Slice const& x, Slice const& y, int32_t mode)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
Expected<Bytes, HostFunctionError>
@@ -418,11 +491,11 @@ floatRootImpl(Slice const& x, int32_t n, int32_t mode)
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const xx(x);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const res(root(xx, n));
detail::WasmNumber const res(root(xx, n));
return res.toBytes();
}
@@ -431,7 +504,6 @@ floatRootImpl(Slice const& x, int32_t n, int32_t mode)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
// LCOV_EXCL_STOP
}
@@ -440,20 +512,20 @@ floatPowerImpl(Slice const& x, int32_t n, int32_t mode)
{
try
{
if ((n < 0) || (n > wasmMaxExponent))
if ((n < 0) || (n > Number::maxExponent))
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const xx(x);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
if (xx == Number() && (n == 0))
return Unexpected(HostFunctionError::INVALID_PARAMS);
detail::Number2 const res(power(xx, n, 1));
detail::WasmNumber const res(power(xx, n, 1));
return res.toBytes();
}
@@ -462,7 +534,6 @@ floatPowerImpl(Slice const& x, int32_t n, int32_t mode)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
// LCOV_EXCL_STOP
}
@@ -475,11 +546,11 @@ floatLogImpl(Slice const& x, int32_t mode)
if (!rm)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const xx(x);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
detail::Number2 const res(log10(xx));
detail::WasmNumber const res(log10(xx));
return res.toBytes();
}
@@ -488,7 +559,6 @@ floatLogImpl(Slice const& x, int32_t mode)
{
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
// LCOV_EXCL_STOP
}
@@ -510,6 +580,42 @@ WasmHostFunctionsImpl::floatFromUint(uint64_t x, int32_t mode) const
return wasm_float::floatFromUintImpl(x, mode);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatFromSTAmount(STAmount const& x, int32_t mode) const
{
return wasm_float::floatFromSTAmountImpl(x, mode);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatFromSTNumber(STNumber const& x, int32_t mode) const
{
return wasm_float::floatFromSTNumberImpl(x, mode);
}
Expected<int64_t, HostFunctionError>
WasmHostFunctionsImpl::floatToInt(Slice const& x, int32_t mode) const
{
return wasm_float::floatToIntImpl(x, mode);
}
Expected<FloatPair, HostFunctionError>
WasmHostFunctionsImpl::floatToMantissaAndExponent(Slice const& x) const
{
return wasm_float::floatToMantissaAndExponentImpl(x);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatNegate(Slice const& x) const
{
return wasm_float::floatNegateImpl(x);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatAbs(Slice const& x) const
{
return wasm_float::floatAbsImpl(x);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatSet(int64_t mantissa, int32_t exponent, int32_t mode) const
{

View File

@@ -90,6 +90,7 @@ getAnyFieldData(STBase const* obj)
}
case STI_AMOUNT:
case STI_NUMBER:
default:
break; // Use serializer
}

View File

@@ -47,7 +47,7 @@ setData(
}
template <class IW>
Expected<int32_t, HostFunctionError>
static Expected<int32_t, HostFunctionError>
getDataInt32(IW const* _runtime, wasm_val_vec_t const* params, int32_t& i)
{
auto const result = params->data[i].of.i32;
@@ -56,7 +56,7 @@ getDataInt32(IW const* _runtime, wasm_val_vec_t const* params, int32_t& i)
}
template <class IW>
Expected<int64_t, HostFunctionError>
static Expected<int64_t, HostFunctionError>
getDataInt64(IW const* _runtime, wasm_val_vec_t const* params, int32_t& i)
{
auto const result = params->data[i].of.i64;
@@ -65,7 +65,7 @@ getDataInt64(IW const* _runtime, wasm_val_vec_t const* params, int32_t& i)
}
template <class T, class IW>
Expected<T, HostFunctionError>
static Expected<T, HostFunctionError>
getDataUnsigned(IW const* runtime, wasm_val_vec_t const* params, int32_t& i)
{
static_assert(std::is_unsigned_v<T>);
@@ -91,21 +91,21 @@ getDataUnsigned(IW const* runtime, wasm_val_vec_t const* params, int32_t& i)
}
template <class IW>
Expected<uint32_t, HostFunctionError>
static Expected<uint32_t, HostFunctionError>
getDataUInt32(IW const* runtime, wasm_val_vec_t const* params, int32_t& i)
{
return getDataUnsigned<uint32_t>(runtime, params, i);
}
template <class IW>
Expected<uint64_t, HostFunctionError>
static Expected<uint64_t, HostFunctionError>
getDataUInt64(IW const* runtime, wasm_val_vec_t const* params, int32_t& i)
{
return getDataUnsigned<uint64_t>(runtime, params, i);
}
template <class IW>
Expected<SFieldCRef, HostFunctionError>
static Expected<SFieldCRef, HostFunctionError>
getDataSField(IW const* _runtime, wasm_val_vec_t const* params, int32_t& i)
{
auto const& m = SField::getKnownCodeToField();
@@ -119,7 +119,7 @@ getDataSField(IW const* _runtime, wasm_val_vec_t const* params, int32_t& i)
}
template <class IW>
Expected<Slice, HostFunctionError>
static Expected<Slice, HostFunctionError>
getDataSlice(IW const* runtime, wasm_val_vec_t const* params, int32_t& i, bool isUpdate = false)
{
int64_t const ptr = params->data[i].of.i32;
@@ -148,7 +148,7 @@ getDataSlice(IW const* runtime, wasm_val_vec_t const* params, int32_t& i, bool i
}
template <class IW>
Expected<uint256, HostFunctionError>
static Expected<uint256, HostFunctionError>
getDataUInt256(IW const* runtime, wasm_val_vec_t const* params, int32_t& i)
{
auto const slice = getDataSlice(runtime, params, i);
@@ -165,7 +165,7 @@ getDataUInt256(IW const* runtime, wasm_val_vec_t const* params, int32_t& i)
}
template <class IW>
Expected<AccountID, HostFunctionError>
static Expected<AccountID, HostFunctionError>
getDataAccountID(IW const* runtime, wasm_val_vec_t const* params, int32_t& i)
{
auto const slice = getDataSlice(runtime, params, i);
@@ -240,7 +240,7 @@ getDataAsset(IW const* runtime, wasm_val_vec_t const* params, int32_t& i)
}
template <class IW>
Expected<std::string_view, HostFunctionError>
static Expected<std::string_view, HostFunctionError>
getDataString(IW const* runtime, wasm_val_vec_t const* params, int32_t& i)
{
auto const slice = getDataSlice(runtime, params, i);
@@ -249,7 +249,7 @@ getDataString(IW const* runtime, wasm_val_vec_t const* params, int32_t& i)
return std::string_view(reinterpret_cast<char const*>(slice->data()), slice->size());
}
std::nullptr_t
static std::nullptr_t
hfResult(wasm_val_vec_t* results, int32_t value)
{
results->data[0] = WASM_I32_VAL(value);
@@ -257,7 +257,7 @@ hfResult(wasm_val_vec_t* results, int32_t value)
return nullptr;
}
std::nullptr_t
static std::nullptr_t
hfResult(wasm_val_vec_t* results, HostFunctionError value)
{
results->data[0] = WASM_I32_VAL(HfErrorToInt(value));
@@ -266,7 +266,7 @@ hfResult(wasm_val_vec_t* results, HostFunctionError value)
}
template <typename T>
std::nullptr_t
static std::nullptr_t
returnResult(
InstanceWrapper const* runtime,
wasm_val_vec_t const* params,
@@ -282,6 +282,9 @@ returnResult(
using t = std::decay_t<decltype(*res)>;
if constexpr (std::is_same_v<t, Bytes>)
{
if (index < 0 || index + 1 >= params->size)
return hfResult(results, HostFunctionError::INTERNAL); // LCOV_EXCL_LINE
return hfResult(
results,
setData(
@@ -293,6 +296,9 @@ returnResult(
}
else if constexpr (std::is_same_v<t, Hash>)
{
if (index < 0 || index + 1 >= params->size)
return hfResult(results, HostFunctionError::INTERNAL); // LCOV_EXCL_LINE
return hfResult(
results,
setData(
@@ -308,6 +314,9 @@ returnResult(
}
else if constexpr (std::is_same_v<t, std::uint32_t>)
{
if (index < 0 || index + 1 >= params->size)
return hfResult(results, HostFunctionError::INTERNAL); // LCOV_EXCL_LINE
auto const resultValue = adjustWasmEndianess(res.value());
return hfResult(
results,
@@ -318,6 +327,49 @@ returnResult(
reinterpret_cast<uint8_t const*>(&resultValue),
static_cast<int32_t>(sizeof(resultValue))));
}
else if constexpr (std::is_same_v<t, int64_t>)
{
if (index < 0 || index + 1 >= params->size)
return hfResult(results, HostFunctionError::INTERNAL); // LCOV_EXCL_LINE
auto const resultValue = adjustWasmEndianess(res.value());
return hfResult(
results,
setData(
runtime,
params->data[index].of.i32,
params->data[index + 1].of.i32,
reinterpret_cast<uint8_t const*>(&resultValue),
static_cast<int32_t>(sizeof(resultValue))));
}
else if constexpr (std::is_same_v<t, FloatPair>)
{
if (index < 0 || index + 3 >= params->size)
return hfResult(results, HostFunctionError::INTERNAL); // LCOV_EXCL_LINE
auto const mantissa = adjustWasmEndianess(res->first);
auto const r1 = setData(
runtime,
params->data[index].of.i32,
params->data[index + 1].of.i32,
reinterpret_cast<uint8_t const*>(&mantissa),
static_cast<int32_t>(sizeof(mantissa)));
if (r1 < 0)
return hfResult(results, r1);
index += 2;
auto const exponent = adjustWasmEndianess(res->second);
auto const r2 = setData(
runtime,
params->data[index].of.i32,
params->data[index + 1].of.i32,
reinterpret_cast<uint8_t const*>(&exponent),
static_cast<int32_t>(sizeof(exponent)));
if (r2 < 0)
return hfResult(results, r2);
return hfResult(results, r1 + r2); // 12
}
else
{
static_assert([] { return false; }(), "Unhandled return type in returnResult");
@@ -1568,6 +1620,149 @@ floatFromUint_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* resu
return returnResult(runtime, params, results, hf->floatFromUint(*x, *rounding), i);
}
wasm_trap_t*
floatFromSTAmount_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
{
if (auto g = checkGas(env); !g)
return g.error(); // LCOV_EXCL_LINE
auto* hf = getHF(env);
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
int i = 0;
auto const x = getDataSlice(runtime, params, i);
if (!x)
return hfResult(results, x.error());
auto serialIter = SerialIter(*x);
std::optional<STAmount> amount;
try
{
amount = STAmount(serialIter, sfGeneric);
}
catch (std::exception const&)
{
amount = std::nullopt;
}
if (!amount)
return hfResult(results, HostFunctionError::INVALID_PARAMS);
i = 4;
auto const rounding = getDataInt32(runtime, params, i);
if (!rounding)
return hfResult(results, rounding.error()); // LCOV_EXCL_LINE
i = 2;
return returnResult(runtime, params, results, hf->floatFromSTAmount(*amount, *rounding), i);
}
wasm_trap_t*
floatFromSTNumber_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
{
if (auto g = checkGas(env); !g)
return g.error(); // LCOV_EXCL_LINE
auto* hf = getHF(env);
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
int i = 0;
auto const x = getDataSlice(runtime, params, i);
if (!x)
return hfResult(results, x.error());
auto serialIter = SerialIter(*x);
std::optional<STNumber> num;
try
{
num = STNumber(serialIter, sfGeneric);
}
catch (std::exception const&)
{
num = std::nullopt;
}
if (!num)
return hfResult(results, HostFunctionError::INVALID_PARAMS);
i = 4;
auto const rounding = getDataInt32(runtime, params, i);
if (!rounding)
return hfResult(results, rounding.error()); // LCOV_EXCL_LINE
i = 2;
return returnResult(runtime, params, results, hf->floatFromSTNumber(*num, *rounding), i);
}
wasm_trap_t*
floatToInt_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
{
if (auto g = checkGas(env); !g)
return g.error(); // LCOV_EXCL_LINE
auto* hf = getHF(env);
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
int i = 0;
auto const x = getDataSlice(runtime, params, i);
if (!x)
return hfResult(results, x.error());
i = 4;
auto const rounding = getDataInt32(runtime, params, i);
if (!rounding)
return hfResult(results, rounding.error()); // LCOV_EXCL_LINE
i = 2;
return returnResult(runtime, params, results, hf->floatToInt(*x, *rounding), i);
}
wasm_trap_t*
floatToMantissaAndExponent_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
{
if (auto g = checkGas(env); !g)
return g.error(); // LCOV_EXCL_LINE
auto* hf = getHF(env);
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
int i = 0;
auto const x = getDataSlice(runtime, params, i);
if (!x)
return hfResult(results, x.error());
i = 2;
return returnResult(runtime, params, results, hf->floatToMantissaAndExponent(*x), i);
}
wasm_trap_t*
floatNegate_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
{
if (auto g = checkGas(env); !g)
return g.error(); // LCOV_EXCL_LINE
auto* hf = getHF(env);
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
int i = 0;
auto const x = getDataSlice(runtime, params, i);
if (!x)
return hfResult(results, x.error());
i = 2;
return returnResult(runtime, params, results, hf->floatNegate(*x), i);
}
wasm_trap_t*
floatAbs_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
{
if (auto g = checkGas(env); !g)
return g.error(); // LCOV_EXCL_LINE
auto* hf = getHF(env);
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
int i = 0;
auto const x = getDataSlice(runtime, params, i);
if (!x)
return hfResult(results, x.error());
i = 2;
return returnResult(runtime, params, results, hf->floatAbs(*x), i);
}
wasm_trap_t*
floatSet_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
{

View File

@@ -76,6 +76,12 @@ setCommonHostFunctions(HostFunctions* hfs, ImportVec& i)
WASM_IMPORT_FUNC2(i, floatFromInt, "float_from_int", hfs, 100);
WASM_IMPORT_FUNC2(i, floatFromUint, "float_from_uint", hfs, 130);
WASM_IMPORT_FUNC2(i, floatFromSTAmount, "float_from_stamount", hfs, 150);
WASM_IMPORT_FUNC2(i, floatFromSTNumber, "float_from_stnumber", hfs, 150);
WASM_IMPORT_FUNC2(i, floatToInt, "float_to_int", hfs, 130);
WASM_IMPORT_FUNC2(i, floatToMantissaAndExponent, "float_to_mantissa_and_exponent", hfs, 130);
WASM_IMPORT_FUNC2(i, floatNegate, "float_negate", hfs, 150);
WASM_IMPORT_FUNC2(i, floatAbs, "float_abs", hfs, 150);
WASM_IMPORT_FUNC2(i, floatSet, "float_set", hfs, 100);
WASM_IMPORT_FUNC2(i, floatCompare, "float_compare", hfs, 80);
WASM_IMPORT_FUNC2(i, floatAdd, "float_add", hfs, 160);

View File

@@ -2065,29 +2065,90 @@ struct HostFuncImpl_test : public beast::unit_test::suite
// clang-format off
int const normalExp = 15;
int const normalExp = 18;
Bytes const floatIntMin = {0x99, 0x20, 0xc4, 0x9b, 0xa5, 0xe3, 0x53, 0xf8}; // -2^63
Bytes const floatIntZero = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // 0
Bytes const floatIntMax = {0xd9, 0x20, 0xc4, 0x9b, 0xa5, 0xe3, 0x53, 0xf8}; // 2^63-1
Bytes const floatUIntMax = {0xd9, 0x46, 0x8d, 0xb8, 0xba, 0xc7, 0x10, 0xcb}; // 2^64-1
Bytes const floatMaxExp = {0xEC, 0x43, 0x8D, 0x7E, 0xA4, 0xC6, 0x80, 0x00}; // 1e(80+15)
Bytes const floatPreMaxExp = {0xEC, 0x03, 0x8D, 0x7E, 0xA4, 0xC6, 0x80, 0x00}; // 1e(79+15)
Bytes const floatMinusMaxExp = {0xAC, 0x43, 0x8D, 0x7E, 0xA4, 0xC6, 0x80, 0x00}; // -1e(80+15)
Bytes const floatMaxIOU = {0xEC, 0x63, 0x86, 0xF2, 0x6F, 0xC0, 0xFF, 0xFF}; // 1e(81+15)-1
Bytes const floatMinExp = {0xC0, 0x43, 0x8D, 0x7E, 0xA4, 0xC6, 0x80, 0x00}; // 1e-96
Bytes const float1 = {0xD4, 0x83, 0x8D, 0x7E, 0xA4, 0xC6, 0x80, 0x00}; // 1
Bytes const floatMinus1 = {0x94, 0x83, 0x8D, 0x7E, 0xA4, 0xC6, 0x80, 0x00}; // -1
Bytes const float1More = {0xD4, 0x83, 0x8D, 0x7E, 0xA4, 0xC6, 0x80, 0x01}; // 1.000 000 000 000 001
Bytes const float2 = {0xD4, 0x87, 0x1A, 0xFD, 0x49, 0x8D, 0x00, 0x00}; // 2
Bytes const float10 = {0xD4, 0xC3, 0x8D, 0x7E, 0xA4, 0xC6, 0x80, 0x00}; // 10
Bytes const floatInvalidZero = {0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // INVALID
Bytes const floatPi = {0xD4, 0x8B, 0x29, 0x43, 0x0A, 0x25, 0x6D, 0x21}; // 3.141592653589793
Bytes const floatIntMin = {0xF3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x01}; // -2^63
Bytes const floatIntZero = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00}; // 0
Bytes const floatIntMax = {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; // 2^63-1
Bytes const floatUIntMax = {0x19, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9A, 0x00, 0x00, 0x00, 0x01}; // 2^64-1
Bytes const floatMaxExp = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00}; // 1e(Number::maxExponent + normalExp)
Bytes const floatPreMaxExp = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF}; // 1e(Number::maxExponent + normalExp - 1)
Bytes const floatMinusMaxExp = {0xF2, 0x1F, 0x49, 0x4C, 0x58, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00}; // -1e(Number::maxExponent + normalExp)
Bytes const floatMinExp = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00}; // 1e(Number::minExponent - normalExp)
Bytes const floatMax = {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x80, 0x00}; // Number::maxRep e(Number::maxExponent - normalExp)
Bytes const floatMaxIOU = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x63, 0xFF, 0x9C, 0x00, 0x00, 0x00, 0x4E}; // 9999999999999999e(96)
Bytes const floatMinIOU = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x9D}; // 1e(-96 - 3 + normalExp = -81)
Bytes const float1 = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // 1
Bytes const floatMinus1 = {0xF2, 0x1F, 0x49, 0x4C, 0x58, 0x9C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // -1
Bytes const float1More = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x03, 0xE8, 0xFF, 0xFF, 0xFF, 0xEE}; // 1.000 000 000 000 001
Bytes const float2 = {0x1B, 0xC1, 0x6D, 0x67, 0x4E, 0xC8, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // 2
Bytes const float10 = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEF}; // 10
Bytes const floatPi = {0x2B, 0x99, 0x2D, 0xDF, 0xA2, 0x32, 0x48, 0xE8, 0xFF, 0xFF, 0xFF, 0xEE}; // 3.141592653589793
Bytes const floatInvalidZero = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00}; // INVALID
Bytes const floatMinus3 = {0xD6, 0x5D, 0xDB, 0xE5, 0x09, 0xD4, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // -3
std::string const invalid = "invalid_data";
// clang-format on
template <class T>
void
printFloats(std::string_view descr, T m, int e)
{
Serializer msg;
Number n;
if constexpr (std::is_signed_v<T>)
{
n = Number(static_cast<int64_t>(m), e);
}
else
{
n = Number(static_cast<uint64_t>(m), e, Number::normalized());
}
STNumber(sfNumber, n).add(msg);
auto const& data = msg.modData();
std::cout << std::setw(24) << descr << " m: " << std::setw(20) << n.mantissa()
<< ", e: " << std::setw(8) << n.exponent() << ", hex: ";
std::cout << std::hex << std::uppercase << std::setfill('0');
for (auto const& c : data)
std::cout << std::setw(2) << (unsigned)c << " ";
std::cout << std::dec << std::setfill(' ') << std::endl;
}
void
printNumbersBin()
{
printFloats("int64.min", std::numeric_limits<int64_t>::min(), 0);
printFloats("zero", 0, 0);
printFloats("int64.max", std::numeric_limits<int64_t>::max(), 0);
printFloats("uint64.max", std::numeric_limits<uint64_t>::max(), 0);
printFloats("Number 1 max exp", 1, Number::maxExponent + normalExp);
printFloats("Number (max exp - 1)", 1, Number::maxExponent + normalExp - 1);
printFloats("Number -1 max exp", -1, Number::maxExponent + normalExp);
printFloats("Number.max", Number::maxRep, Number::maxExponent);
printFloats("Number min positive", 1, Number::minExponent + normalExp);
printFloats(
"Number.min", std::numeric_limits<int64_t>::min(), Number::maxExponent - normalExp);
printFloats("STAmount.max", STAmount::cMaxValue, STAmount::cMaxOffset);
printFloats("STAmount min positive", STAmount::cMinValue, STAmount::cMinOffset);
printFloats("one", 1, 0);
printFloats("-one", -1, 0);
printFloats("1,00...01", 1'000'000'000'000'001, -15);
printFloats("two", 2, 0);
printFloats("ten", 10, 0);
printFloats("pi", 3141592653589793, -15);
printFloats("-three", -3, 0);
return;
}
void
testTraceFloat()
{
@@ -2236,38 +2297,38 @@ struct HostFuncImpl_test : public beast::unit_test::suite
}
{
auto const result = hfs.floatSet(1, wasmMaxExponent + normalExp + 1, 0);
auto const result = hfs.floatSet(1, Number::maxExponent + normalExp + 1, 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_COMPUTATION_ERROR);
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatSet(1, wasmMinExponent + normalExp - 1, 0);
auto const result = hfs.floatSet(1, Number::minExponent + normalExp - 1, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatIntZero);
}
{
auto const result = hfs.floatSet(1, wasmMaxExponent + normalExp, 0);
auto const result = hfs.floatSet(1, Number::maxExponent + normalExp, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMaxExp);
}
{
auto const result = hfs.floatSet(-1, wasmMaxExponent + normalExp, 0);
auto const result = hfs.floatSet(-1, Number::maxExponent + normalExp, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMinusMaxExp);
}
{
auto const result = hfs.floatSet(1, wasmMaxExponent + normalExp - 1, 0);
auto const result = hfs.floatSet(1, Number::maxExponent + normalExp - 1, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatPreMaxExp);
}
{
auto const result = hfs.floatSet(STAmount::cMaxValue, wasmMaxExponent, 0);
auto const result = hfs.floatSet(STAmount::cMaxValue, STAmount::cMaxOffset, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMaxIOU);
}
{
auto const result = hfs.floatSet(1, wasmMinExponent + normalExp, 0);
auto const result = hfs.floatSet(1, Number::minExponent - normalExp, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMinExp);
}
@@ -2275,12 +2336,6 @@ struct HostFuncImpl_test : public beast::unit_test::suite
auto const result = hfs.floatSet(10, -1, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == float1);
}
{
auto const result = hfs.floatSet(1, Number::maxExponent + normalExp + 1, 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
}
void
@@ -2312,15 +2367,6 @@ struct HostFuncImpl_test : public beast::unit_test::suite
BEAST_EXPECT(!result && result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto x = floatMaxExp;
// exp = 81 + 97 = 178
x[1] |= 0x80;
x[1] &= 0xBF;
auto const result = hfs.floatCompare(makeSlice(x), makeSlice(floatMaxExp));
BEAST_EXPECT(!result && result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatCompare(makeSlice(floatIntMin), makeSlice(floatIntZero));
BEAST_EXPECT(result) && BEAST_EXPECT(*result == 2);
@@ -2368,9 +2414,9 @@ struct HostFuncImpl_test : public beast::unit_test::suite
}
{
// max IOU is too small to make any change
auto const result = hfs.floatAdd(makeSlice(floatMaxIOU), makeSlice(floatMaxExp), 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_COMPUTATION_ERROR);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMaxExp);
}
{
@@ -2379,8 +2425,9 @@ struct HostFuncImpl_test : public beast::unit_test::suite
}
{
// Number can't hold int64.min, it is rounded and we get -3, not -1
auto const result = hfs.floatAdd(makeSlice(floatIntMax), makeSlice(floatIntMin), 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatIntZero);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMinus3);
}
}
@@ -2416,9 +2463,8 @@ struct HostFuncImpl_test : public beast::unit_test::suite
{
auto const result =
hfs.floatSubtract(makeSlice(floatMaxIOU), makeSlice(floatMinusMaxExp), 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_COMPUTATION_ERROR);
hfs.floatSubtract(makeSlice(floatMinusMaxExp), makeSlice(floatMaxIOU), 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMinusMaxExp);
}
{
@@ -2464,7 +2510,7 @@ struct HostFuncImpl_test : public beast::unit_test::suite
}
{
auto const result = hfs.floatMultiply(makeSlice(floatMaxIOU), makeSlice(float1More), 0);
auto const result = hfs.floatMultiply(makeSlice(floatMax), makeSlice(float1More), 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
@@ -2526,7 +2572,7 @@ struct HostFuncImpl_test : public beast::unit_test::suite
auto const y = hfs.floatSet(STAmount::cMaxValue, -normalExp - 1, 0); // 0.9999999...
if (BEAST_EXPECT(y))
{
auto const result = hfs.floatDivide(makeSlice(floatMaxIOU), makeSlice(*y), 0);
auto const result = hfs.floatDivide(makeSlice(floatMax), makeSlice(*y), 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
@@ -2643,23 +2689,17 @@ struct HostFuncImpl_test : public beast::unit_test::suite
}
{
auto const result = hfs.floatPower(makeSlice(floatMaxIOU), 2, 0);
auto const result = hfs.floatPower(makeSlice(floatMax), 2, 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
{
auto const result = hfs.floatPower(makeSlice(floatMaxIOU), 81, 0);
auto const result = hfs.floatPower(makeSlice(floatMax), Number::maxExponent + 1, 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatPower(makeSlice(floatMaxIOU), 2, 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
{
auto const result = hfs.floatPower(makeSlice(floatMaxIOU), 0, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == float1);
@@ -2714,48 +2754,8 @@ struct HostFuncImpl_test : public beast::unit_test::suite
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
// perf test logs
// {
// auto const result = hfs.floatLog(makeSlice(floatPi), 0);
// if (BEAST_EXPECT(result))
// {
// std::cout << "lg(" << floatToString(makeSlice(floatPi))
// << ") = " << floatToString(makeSlice(*result))
// << std::endl;
// }
// }
// {
// auto const result = hfs.floatLog(makeSlice(floatIntMax), 0);
// if (BEAST_EXPECT(result))
// {
// std::cout << "lg(" << floatToString(makeSlice(floatIntMax))
// << ") = " << floatToString(makeSlice(*result))
// << std::endl;
// }
// }
// {
// auto const result = hfs.floatLog(makeSlice(floatMaxExp), 0);
// if (BEAST_EXPECT(result))
// {
// std::cout << "lg(" << floatToString(makeSlice(floatMaxExp))
// << ") = " << floatToString(makeSlice(*result))
// << std::endl;
// }
// }
// {
// auto const result = hfs.floatLog(makeSlice(floatMaxIOU), 0);
// if (BEAST_EXPECT(result))
// {
// std::cout << "lg(" << floatToString(makeSlice(floatMaxIOU))
// << ") = " << floatToString(makeSlice(*result))
// << std::endl;
// }
// }
{
auto const x = hfs.floatSet(9'500'000'000'000'001, -14, 0); // almost 80+15
auto const x = hfs.floatSet(32'786, 0, 0);
if (BEAST_EXPECT(x))
{
auto const result = hfs.floatLog(makeSlice(floatMaxExp), 0);
@@ -2774,7 +2774,7 @@ struct HostFuncImpl_test : public beast::unit_test::suite
{
auto const x = hfs.floatSet(1000, 0, 0); // 1000
auto const y = hfs.floatSet(3, 0, 0); // 0.1
auto const y = hfs.floatSet(3, 0, 0); // 3
if (BEAST_EXPECT(x && y))
{
auto const result = hfs.floatLog(makeSlice(*x), 0);
@@ -2783,8 +2783,8 @@ struct HostFuncImpl_test : public beast::unit_test::suite
}
{
auto const x = hfs.floatSet(1, -2, 0); // 0.01
auto const y = hfs.floatSet(-2'000'000'000'000'000ll, -15, 0); // -2
auto const x = hfs.floatSet(1, -2, 0); // 0.01
auto const y = hfs.floatSet(-1'999'999'999'999'999'999, -normalExp, 0); // -2
if (BEAST_EXPECT(x && y))
{
auto const result = hfs.floatLog(makeSlice(*x), 0);
@@ -2796,7 +2796,6 @@ struct HostFuncImpl_test : public beast::unit_test::suite
void
testFloatSpecialCases()
{
testcase("float Xrp+Mpt");
using namespace test::jtx;
Env env{*this};
@@ -2805,60 +2804,472 @@ struct HostFuncImpl_test : public beast::unit_test::suite
auto const dummyEscrow = keylet::escrow(env.master, env.seq(env.master));
WasmHostFunctionsImpl const hfs(ac, dummyEscrow);
auto const y = hfs.floatSet(20, 0, 0);
if (!BEAST_EXPECT(y))
return;
Bytes x(8);
// XRP
memset(x.data(), 0, x.size());
x[0] = 0x40;
x[7] = 10;
{
auto const result = hfs.floatCompare(makeSlice(x), makeSlice(float10));
BEAST_EXPECT(!result && result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatAdd(makeSlice(float10), makeSlice(x), 0);
BEAST_EXPECT(!result && result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
// MPT
memset(x.data(), 0, x.size());
x[0] = 0x60;
x[7] = 10;
{
auto const result = hfs.floatCompare(makeSlice(x), makeSlice(float10));
BEAST_EXPECT(!result && result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatAdd(makeSlice(float10), makeSlice(x), 0);
BEAST_EXPECT(!result && result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
testcase("float non-canonical");
{ // non-canonical mantissa 10 000 000 000 000 000
Bytes x = float1;
*reinterpret_cast<uint64_t*>(x.data()) = 0x0000C16FF286A3D4ull;
{ // non-canonical mantissa 100000e-4
Bytes const y = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86, 0xA0, 0xFF, 0xFF, 0xFF, 0xFC};
auto const result = hfs.floatCompare(makeSlice(y), makeSlice(float10));
BEAST_EXPECT(result && *result == 0);
}
}
void
testFloatFromSTAmount()
{
testcase("floatFromSTAmount");
using namespace test::jtx;
Env env{*this};
OpenView ov{*env.current()};
ApplyContext ac = createApplyContext(env, ov);
auto const dummyEscrow = keylet::escrow(env.master, env.seq(env.master));
WasmHostFunctionsImpl const hfs(ac, dummyEscrow);
{
STAmount const amount = XRP(100);
auto const result = hfs.floatFromSTAmount(amount, -1);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
STAmount const amount = XRP(100);
auto const result = hfs.floatFromSTAmount(amount, 4);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
STAmount const amount = XRP(0);
auto const result = hfs.floatFromSTAmount(amount, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatIntZero);
}
{
STAmount const amount = XRP(-1);
auto const y = hfs.floatSet(-1 * 1'000'000, 0, 0);
if (BEAST_EXPECT(y))
{
auto const result = hfs.floatCompare(makeSlice(x), makeSlice(float1));
BEAST_EXPECT(!result && result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
auto const result = hfs.floatFromSTAmount(amount, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == *y);
}
}
{
auto const y = hfs.floatSet(9223372036854776, 3, 0);
STAmount const amount(noIssue(), std::numeric_limits<int64_t>::max());
auto const result = hfs.floatFromSTAmount(amount, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == *y);
}
{
bool ex = false;
try
{
STAmount const amount(noIssue(), -1, Number::maxExponent + normalExp);
[[maybe_unused]] auto const r = hfs.floatFromSTAmount(amount, 0);
}
catch (...)
{
ex = true;
}
BEAST_EXPECT(ex);
}
auto const USD = env.master["USD"];
{
STAmount const amount(
IOUAmount(STAmount::cMinValue, STAmount::cMinOffset), USD.issue());
auto const result = hfs.floatFromSTAmount(amount, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMinIOU);
}
{
STAmount const amount(
IOUAmount(STAmount::cMaxValue, STAmount::cMaxOffset), USD.issue());
auto const result = hfs.floatFromSTAmount(amount, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMaxIOU);
}
}
void
testFloatFromSTNumber()
{
testcase("floatFromSTNumber");
using namespace test::jtx;
Env env{*this};
OpenView ov{*env.current()};
ApplyContext ac = createApplyContext(env, ov);
auto const dummyEscrow = keylet::escrow(env.master, env.seq(env.master));
WasmHostFunctionsImpl const hfs(ac, dummyEscrow);
// Test with invalid rounding mode
{
STNumber const num(sfNumber, Number(123, 0));
auto const result = hfs.floatFromSTNumber(num, -1);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
STNumber const num(sfNumber, Number(123, 0));
auto const result = hfs.floatFromSTNumber(num, 4);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
STNumber const num(
sfNumber, Number(std::numeric_limits<uint64_t>::max(), 0, Number::normalized()));
auto const result = hfs.floatFromSTNumber(num, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatUIntMax);
}
{
STNumber const num(sfNumber, Number(-1, Number::maxExponent + normalExp));
auto const result = hfs.floatFromSTNumber(num, 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMinusMaxExp);
}
}
void
testFloatToInt()
{
testcase("floatToInt");
using namespace test::jtx;
Env env{*this};
OpenView ov{*env.current()};
ApplyContext ac = createApplyContext(env, ov);
auto const dummyEscrow = keylet::escrow(env.master, env.seq(env.master));
WasmHostFunctionsImpl const hfs(ac, dummyEscrow);
{
auto const result = hfs.floatToInt(makeSlice(float1), -1);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatToInt(makeSlice(float1), 4);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatToInt(Slice(), 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatToInt(makeSlice(invalid), 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatToInt(makeSlice(floatIntZero), 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == 0);
// roundtrip
auto const result2 = hfs.floatFromInt(*result, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == floatIntZero);
}
{
auto const result = hfs.floatToInt(makeSlice(float1), 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == 1);
// roundtrip
auto const result2 = hfs.floatFromInt(*result, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == float1);
}
{
auto const result = hfs.floatToInt(makeSlice(floatMinus1), 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == -1);
// roundtrip
auto const result2 = hfs.floatFromInt(*result, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == floatMinus1);
}
{
auto const result = hfs.floatToInt(makeSlice(floatIntMax), 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == std::numeric_limits<int64_t>::max());
// roundtrip
auto const result2 = hfs.floatFromInt(*result, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == floatIntMax);
}
{
// Number can't hold int64.min, it is rounded and we get int64_t.min - 3, which doesn't
// fit into int64
auto const result = hfs.floatToInt(makeSlice(floatIntMin), 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
{
auto const result = hfs.floatToInt(makeSlice(floatUIntMax), 0);
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_COMPUTATION_ERROR);
}
// Test rounding modes with pi (3.141592653589793)
{
// to_nearest (mode 0): should round to 3
auto const result = hfs.floatToInt(makeSlice(floatPi), 0);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == 3);
}
{
// towards_zero (mode 1): should truncate to 3
auto const result = hfs.floatToInt(makeSlice(floatPi), 1);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == 3);
}
{
// downward (mode 2): should round down to 3
auto const result = hfs.floatToInt(makeSlice(floatPi), 2);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == 3);
}
{
// upward (mode 3): should round up to 4
auto const result = hfs.floatToInt(makeSlice(floatPi), 3);
BEAST_EXPECT(result) && BEAST_EXPECT(*result == 4);
}
}
void
testFloatToMantissaAndExponent()
{
testcase("floatToMantissaAndExponent");
using namespace test::jtx;
Env env{*this};
OpenView ov{*env.current()};
ApplyContext ac = createApplyContext(env, ov);
auto const dummyEscrow = keylet::escrow(env.master, env.seq(env.master));
WasmHostFunctionsImpl const hfs(ac, dummyEscrow);
{
auto const result = hfs.floatToMantissaAndExponent(makeSlice(invalid));
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatToMantissaAndExponent(makeSlice(floatIntZero));
BEAST_EXPECT(result) && BEAST_EXPECT(result->first == 0) &&
BEAST_EXPECT(result->second == std::numeric_limits<int32_t>::min());
// roundtrip
auto const result2 = hfs.floatSet(result->first, result->second, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == floatIntZero);
}
{
auto const result = hfs.floatToMantissaAndExponent(makeSlice(float1));
BEAST_EXPECT(result) && BEAST_EXPECT(result->first == 1000000000000000000) &&
BEAST_EXPECT(result->second == -normalExp);
// roundtrip
auto const result2 = hfs.floatSet(result->first, result->second, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == float1);
}
{
auto const result = hfs.floatToMantissaAndExponent(makeSlice(floatMinus1));
BEAST_EXPECT(result) && BEAST_EXPECT(result->first == -1000000000000000000) &&
BEAST_EXPECT(result->second == -normalExp);
// roundtrip
auto const result2 = hfs.floatSet(result->first, result->second, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == floatMinus1);
}
{
auto const result = hfs.floatToMantissaAndExponent(makeSlice(float10));
BEAST_EXPECT(result) && BEAST_EXPECT(result->first == 1000000000000000000) &&
BEAST_EXPECT(result->second == -normalExp + 1);
// roundtrip
auto const result2 = hfs.floatSet(result->first, result->second, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == float10);
}
{
auto const result = hfs.floatToMantissaAndExponent(makeSlice(floatPi));
BEAST_EXPECT(result) && BEAST_EXPECT(result->first == 3141592653589793000) &&
BEAST_EXPECT(result->second == -normalExp);
// roundtrip
auto const result2 = hfs.floatSet(result->first, result->second, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == floatPi);
}
{
auto const result = hfs.floatToMantissaAndExponent(makeSlice(floatIntMax));
BEAST_EXPECT(result) &&
BEAST_EXPECT(result->first == std::numeric_limits<int64_t>::max()) &&
BEAST_EXPECT(result->second == 0);
// roundtrip
auto const result2 = hfs.floatSet(result->first, result->second, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == floatIntMax);
}
{
auto const result = hfs.floatToMantissaAndExponent(makeSlice(floatIntMin));
BEAST_EXPECT(result) &&
BEAST_EXPECT(result->first == (std::numeric_limits<int64_t>::min() / 10) - 1) &&
BEAST_EXPECT(result->second == 1);
// roundtrip
auto const result2 = hfs.floatSet(result->first, result->second, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == floatIntMin);
}
{
auto const result = hfs.floatToMantissaAndExponent(makeSlice(floatMax));
BEAST_EXPECT(result) && BEAST_EXPECT(result->first == Number::maxRep) &&
BEAST_EXPECT(result->second == Number::maxExponent);
// roundtrip
auto const result2 = hfs.floatSet(result->first, result->second, 0);
BEAST_EXPECT(result2) && BEAST_EXPECT(*result2 == floatMax);
}
}
void
testFloatNegate()
{
testcase("floatNegate");
using namespace test::jtx;
Env env{*this};
OpenView ov{*env.current()};
ApplyContext ac = createApplyContext(env, ov);
auto const dummyEscrow = keylet::escrow(env.master, env.seq(env.master));
WasmHostFunctionsImpl const hfs(ac, dummyEscrow);
{
auto const result = hfs.floatNegate(makeSlice(invalid));
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatNegate(makeSlice(floatIntZero));
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatIntZero);
}
{
auto const result = hfs.floatNegate(makeSlice(float1));
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMinus1);
}
{
auto const result = hfs.floatNegate(makeSlice(floatMinus1));
BEAST_EXPECT(result) && BEAST_EXPECT(*result == float1);
}
{
auto const result = hfs.floatNegate(makeSlice(floatIntMax));
auto const expected = hfs.floatFromInt(std::numeric_limits<int64_t>::min() + 1, 0);
BEAST_EXPECT(result && expected) && BEAST_EXPECT(*result == *expected);
}
{
auto const result = hfs.floatNegate(makeSlice(floatMaxExp));
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMinusMaxExp);
}
{
auto const result = hfs.floatNegate(makeSlice(floatPi));
auto const negPi = hfs.floatNegate(makeSlice(*result));
BEAST_EXPECT(result && negPi) && BEAST_EXPECT(*negPi == floatPi);
}
}
void
testFloatAbs()
{
testcase("floatAbs");
using namespace test::jtx;
Env env{*this};
OpenView ov{*env.current()};
ApplyContext ac = createApplyContext(env, ov);
auto const dummyEscrow = keylet::escrow(env.master, env.seq(env.master));
WasmHostFunctionsImpl const hfs(ac, dummyEscrow);
{
auto const result = hfs.floatAbs(makeSlice(invalid));
BEAST_EXPECT(!result) &&
BEAST_EXPECT(result.error() == HostFunctionError::FLOAT_INPUT_MALFORMED);
}
{
auto const result = hfs.floatAbs(makeSlice(floatIntZero));
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatIntZero);
}
{
auto const result = hfs.floatAbs(makeSlice(float1));
BEAST_EXPECT(result) && BEAST_EXPECT(*result == float1);
}
{
auto const result = hfs.floatAbs(makeSlice(floatMinus1));
BEAST_EXPECT(result) && BEAST_EXPECT(*result == float1);
}
{
auto const result = hfs.floatAbs(makeSlice(floatIntMax));
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatIntMax);
}
{
auto const result = hfs.floatAbs(makeSlice(floatIntMin));
auto const negated = hfs.floatNegate(makeSlice(floatIntMin));
BEAST_EXPECT(result && negated) && BEAST_EXPECT(*result == *negated);
}
{
auto const result = hfs.floatAbs(makeSlice(floatMinusMaxExp));
BEAST_EXPECT(result) && BEAST_EXPECT(*result == floatMaxExp);
}
{
auto const result = hfs.floatAbs(makeSlice(floatMinus3));
auto const expected = hfs.floatFromInt(3, 0);
BEAST_EXPECT(result && expected) && BEAST_EXPECT(*result == *expected);
}
}
void
testFloats()
{
// for checking binary formats manually
// printNumbersBin();
testTraceFloat();
testFloatFromInt();
testFloatFromUint();
testFloatFromSTAmount();
testFloatFromSTNumber();
testFloatToInt();
testFloatToMantissaAndExponent();
testFloatNegate();
testFloatAbs();
testFloatSet();
testFloatCompare();
testFloatAdd();

View File

@@ -458,6 +458,42 @@ public:
return wasm_float::floatFromUintImpl(x, mode);
}
Expected<Bytes, HostFunctionError>
floatFromSTAmount(STAmount const& x, int32_t mode) const override
{
return wasm_float::floatFromSTAmountImpl(x, mode);
}
Expected<Bytes, HostFunctionError>
floatFromSTNumber(STNumber const& x, int32_t mode) const override
{
return wasm_float::floatFromSTNumberImpl(x, mode);
}
Expected<int64_t, HostFunctionError>
floatToInt(Slice const& x, int32_t mode) const override
{
return wasm_float::floatToIntImpl(x, mode);
}
virtual Expected<FloatPair, HostFunctionError>
floatToMantissaAndExponent(Slice const& x) const override
{
return wasm_float::floatToMantissaAndExponentImpl(x);
}
Expected<Bytes, HostFunctionError>
floatNegate(Slice const& x) const override
{
return wasm_float::floatNegateImpl(x);
}
Expected<Bytes, HostFunctionError>
floatAbs(Slice const& x) const override
{
return wasm_float::floatAbsImpl(x);
}
Expected<Bytes, HostFunctionError>
floatSet(int64_t mantissa, int32_t exponent, int32_t mode) const override
{

View File

@@ -599,7 +599,7 @@ struct Wasm_test : public beast::unit_test::suite
TestHostFunctions hfs(env, 0);
auto re = runEscrowWasm(floatTestWasm, hfs, 200'000, funcName, {});
checkResult(re, 1, 110'699);
checkResult(re, 1, 167'965);
env.close();
}
@@ -608,7 +608,7 @@ struct Wasm_test : public beast::unit_test::suite
TestHostFunctions hfs(env, 0);
auto re = runEscrowWasm(float0Wasm, hfs, 100'000, funcName, {});
checkResult(re, 1, 4'259);
checkResult(re, 1, 4'309);
env.close();
}
}
@@ -787,7 +787,7 @@ struct Wasm_test : public beast::unit_test::suite
auto re = engine.run(badAlignWasm, hfs, 1'000'000, "test", {}, imports, env.journal);
if (BEAST_EXPECTS(re, transToken(re.error())))
{
BEAST_EXPECTS(re->result == 0x684f7941, std::to_string(re->result));
BEAST_EXPECTS(re->result == 0x47308594, std::to_string(re->result));
}
}

View File

@@ -653,119 +653,267 @@ extern std::string const codecovTestsWasmHex =
"2d657874";
extern std::string const floatTestsWasmHex =
"0061736d0100000001430860077f7f7f7f7f7f7f017f60057f7f7f7f7f017f60047f7f7f7f017f60067f7f7f7f7f7f"
"017f60047e7f7f7f017f60057f7e7f7f7f017f60037f7f7e017f6000017f02c9020e08686f73745f6c696205747261"
"6365000108686f73745f6c69620e666c6f61745f66726f6d5f696e74000408686f73745f6c69621274726163655f6f"
"70617175655f666c6f6174000208686f73745f6c69620f666c6f61745f66726f6d5f75696e74000108686f73745f6c"
"696209666c6f61745f736574000508686f73745f6c69620d666c6f61745f636f6d70617265000208686f73745f6c69"
"6209666c6f61745f616464000008686f73745f6c69620e666c6f61745f7375627472616374000008686f73745f6c69"
"620e666c6f61745f6d756c7469706c79000008686f73745f6c69620c666c6f61745f646976696465000008686f7374"
"5f6c696209666c6f61745f706f77000308686f73745f6c69620974726163655f6e756d000608686f73745f6c69620a"
"666c6f61745f726f6f74000308686f73745f6c696209666c6f61745f6c6f6700010302010705030100110619037f01"
"418080c0000b7f0041d28ac0000b7f0041e08ac0000b072e04066d656d6f727902000666696e697368000e0a5f5f64"
"6174615f656e6403010b5f5f686561705f6261736503020af20e01ef0e01047f230041206b22012400418080c00041"
"1d41014100410010001a200142003703100240428ce000200141106a22004108410010014108460440419d80c00041"
"172000410810021a41b480c000411e20004108410110001a0c010b41d280c000411e41014100410010001a0b200142"
"8ce0003703180240200141186a4108200141106a2200410841001003410846044041f080c00041172000410810021a"
"0c010b418781c000411e41014100410010001a0b0240410242fb00200141106a2200410841001004410846044041a5"
"81c00041212000410810021a0c010b41c681c000412641014100410010001a0b41ec81c0004115418182c000410810"
"021a419182c0004116418982c000410810021a41a782c000411b41014100410010001a200142003703180240420120"
"0141186a2200410841001001410846044041c282c000410f2000410810021a0c010b41d182c0004116410141004100"
"10001a0b0240200141186a4108418182c0004108100545044041e782c000411b41014100410010001a0c010b418283"
"c000411b41014100410010001a0b0240200141186a4108418982c000410810054101460440419d83c0004123410141"
"00410010001a0c010b41c083c000412441014100410010001a0b0240418982c0004108200141186a41081005410246"
"044041e483c000412341014100410010001a0c010b418784c000412441014100410010001a0b41ab84c00041204101"
"4100410010001a200142d487b6f4c7d4b1c000370310410921000340200141106a22024108418182c0004108200241"
"08410010061a200041016b22000d000b20014200370318420a200141186a22004108410010011a0240200041082002"
"4108100545044041cb84c000411441014100410010001a0c010b41df84c000411341014100410010001a0b410b2100"
"0340200141106a22024108418182c000410820024108410010071a200041016b22000d000b024020024108418982c0"
"004108100545044041f284c000411941014100410010001a0c010b418b85c000411841014100410010001a0b41a385"
"c000412341014100410010001a20014200370300420a20014108410010011a200142d487b6f4c7d4b1c00037030841"
"0621000340200141086a220241082001410820024108410010081a200041016b22000d000b2001420037031042c084"
"3d200141106a22004108410010011a02402000410820024108100545044041c685c000411941014100410010001a0c"
"010b41df85c000411841014100410010001a0b410721000340200141086a220241082001410820024108410010091a"
"200041016b22000d000b20014200370318417f4201200141186a22004108410010041a024020024108200041081005"
"45044041f785c000411741014100410010001a0c010b418e86c000411641014100410010001a0b41a486c000411741"
"014100410010001a20014200370308418182c00041084103200141086a220041084100100a1a41bb86c00041122000"
"410810021a418982c00041084106200041084100100a1a41cd86c00041182000410810021a20014200370310420920"
"0141106a22024108410010011a200241084102200041084100100a1a41e586c00041142000410810021a2002410841"
"00200041084100100a1a41f986c00041172000410810021a200142003703184200200141186a22034108410010011a"
"200341084102200041084100100a1a419087c00041142000410810021a41a487c00041382003410841002000410841"
"00100aac100b1a41dc87c000411841014100410010001a20014200370308420920004108410010011a200142003703"
"10200041084102200241084100100c1a41f487c00041122002410810021a200041084103200241084100100c1a4186"
"88c00041122002410810021a2001420037031842c0843d20034108410010011a200341084103200241084100100c1a"
"419888c00041182002410810021a200341084106200241084100100c1a41b088c000411c2002410810021a41cc88c0"
"00411741014100410010001a2001420037031042c0843d20024108410010011a200142003703182002410820034108"
"4100100d1a41e388c00041142003410810021a41f788c000411a41014100410010001a20014200370318418182c000"
"4108418982c000410820034108410010081a0240418982c0004108200341081005450440419189c000411641014100"
"410010001a0c010b41a789c000411541014100410010001a0b418982c0004108418982c0004108200141186a220041"
"08410010081a0240418182c000410820004108100545044041bc89c000411741014100410010001a0c010b41d389c0"
"00411641014100410010001a0b41e989c000411a41014100410010001a2001420037031020014200370318420a2001"
"41186a22024108410010011a418182c000410820024108200141106a22004108410010091a41838ac0004119200041"
"0810021a418182c00041082000410820004108410010091a419c8ac000410f2000410810021a024020024108200041"
"08100545044041ab8ac000411441014100410010001a0c010b41bf8ac000411341014100410010001a0b200141206a"
"240041010b0bdc0a0100418080c0000bd20a0a24242420746573745f666c6f61745f66726f6d5f7761736d20242424"
"2020666c6f61742066726f6d206936342031323330303a2020666c6f61742066726f6d206936342031323330302061"
"73204845583a2020666c6f61742066726f6d206936342031323330303a206661696c65642020666c6f61742066726f"
"6d207536342031323330303a2020666c6f61742066726f6d207536342031323330303a206661696c65642020666c6f"
"61742066726f6d2065787020322c206d616e7469737361203132333a2020666c6f61742066726f6d2065787020322c"
"206d616e746973736120333a206661696c65642020666c6f61742066726f6d20636f6e737420313ad4838d7ea4c680"
"0094838d7ea4c680002020666c6f61742066726f6d20636f6e7374202d313a0a24242420746573745f666c6f61745f"
"636f6d70617265202424242020666c6f61742066726f6d20313a2020666c6f61742066726f6d20313a206661696c65"
"642020666c6f61742066726f6d2031203d3d20464c4f41545f4f4e452020666c6f61742066726f6d203120213d2046"
"4c4f41545f4f4e452020666c6f61742066726f6d2031203e20464c4f41545f4e454741544956455f4f4e452020666c"
"6f61742066726f6d203120213e20464c4f41545f4e454741544956455f4f4e452020464c4f41545f4e454741544956"
"455f4f4e45203c20666c6f61742066726f6d20312020464c4f41545f4e454741544956455f4f4e4520213c20666c6f"
"61742066726f6d20310a24242420746573745f666c6f61745f6164645f737562747261637420242424202072657065"
"61746564206164643a20676f6f6420207265706561746564206164643a206261642020726570656174656420737562"
"74726163743a20676f6f64202072657065617465642073756274726163743a206261640a24242420746573745f666c"
"6f61745f6d756c7469706c795f6469766964652024242420207265706561746564206d756c7469706c793a20676f6f"
"6420207265706561746564206d756c7469706c793a2062616420207265706561746564206469766964653a20676f6f"
"6420207265706561746564206469766964653a206261640a24242420746573745f666c6f61745f706f772024242420"
"20666c6f61742063756265206f6620313a2020666c6f61742036746820706f776572206f66202d313a2020666c6f61"
"7420737175617265206f6620393a2020666c6f61742030746820706f776572206f6620393a2020666c6f6174207371"
"75617265206f6620303a2020666c6f61742030746820706f776572206f6620302028657870656374696e6720494e56"
"414c49445f504152414d53206572726f72293a0a24242420746573745f666c6f61745f726f6f74202424242020666c"
"6f61742073717274206f6620393a2020666c6f61742063627274206f6620393a2020666c6f61742063627274206f66"
"20313030303030303a2020666c6f61742036746820726f6f74206f6620313030303030303a0a24242420746573745f"
"666c6f61745f6c6f672024242420206c6f675f3130206f6620313030303030303a0a24242420746573745f666c6f61"
"745f6e65676174652024242420206e656761746520636f6e737420313a20676f6f6420206e656761746520636f6e73"
"7420313a2062616420206e656761746520636f6e7374202d313a20676f6f6420206e656761746520636f6e7374202d"
"313a206261640a24242420746573745f666c6f61745f696e76657274202424242020696e76657274206120666c6f61"
"742066726f6d2031303a2020696e7665727420616761696e3a2020696e766572742074776963653a20676f6f642020"
"696e766572742074776963653a20626164004d0970726f64756365727302086c616e6775616765010452757374000c"
"70726f6365737365642d6279010572757374631d312e38372e30202831373036376539616320323032352d30352d30"
"3929002c0f7461726765745f6665617475726573022b0f6d757461626c652d676c6f62616c732b087369676e2d6578"
"74";
"0061736d01000000014f0a60057f7f7f7f7f017f60077f7f7f7f7f7f7f017f60047f7f7f7f017f60067f7f7f7f7f7f"
"017f60047e7f7f7f017f60057f7e7f7f7f017f60037f7f7e017f60037f7f7f006000017f60027f7f017f02ba031308"
"686f73745f6c6962057472616365000008686f73745f6c69620e666c6f61745f66726f6d5f696e74000408686f7374"
"5f6c69620f666c6f61745f66726f6d5f75696e74000008686f73745f6c696209666c6f61745f736574000508686f73"
"745f6c69620d666c6f61745f636f6d70617265000208686f73745f6c696209666c6f61745f616464000108686f7374"
"5f6c69620e666c6f61745f7375627472616374000108686f73745f6c69620e666c6f61745f6d756c7469706c790001"
"08686f73745f6c69620c666c6f61745f646976696465000108686f73745f6c696209666c6f61745f706f7700030868"
"6f73745f6c69620974726163655f6e756d000608686f73745f6c69620a666c6f61745f726f6f74000308686f73745f"
"6c696209666c6f61745f6c6f67000003656e760c666c6f61745f746f5f696e74000003656e761e666c6f61745f746f"
"5f6d616e74697373615f616e645f6578706f6e656e74000303656e760c666c6f61745f6e6567617465000203656e76"
"09666c6f61745f616273000203656e7613666c6f61745f66726f6d5f7374616d6f756e74000003656e7613666c6f61"
"745f66726f6d5f73746e756d626572000003040307080905030100110619037f01418080c0000b7f0041a0a1c0000b"
"7f0041a0a1c0000b072e04066d656d6f727902000666696e69736800140a5f5f646174615f656e6403010b5f5f6865"
"61705f6261736503020ae52c031f002000200141014100410010001a418080c00041022002410c410110001a0bff2b"
"020f7f017e23004180016b22002400418280c000411d41014100410010001a200041f8006a41003602002000420037"
"03700240428ce000200041f0006a2202410c410010012201410c460440419f80c00041172002101341b680c000411e"
"2002410c410110001a0c010b41d480c000411e41014100410010001a0b2000428ce0003703600240200041e0006a41"
"08200041f0006a2202410c41001002410c4604402001410c46210841f280c0004117200210130c010b418981c00041"
"1e41014100410010001a0b0240410242fb00200041f0006a2201410c41001003410c46044041a781c0004121200110"
"130c010b41c881c000412641014100410010001a410021080b41ee81c0004115418382c0001013418f82c000411641"
"a582c000101341b182c000411b41014100410010001a200041f8006a41003602002000420037037002404201200041"
"f0006a2202410c410010012201410c46044041cc82c000410f200210130c010b41db82c00041164101410041001000"
"1a0b027f200041f0006a410c418382c000410c100445044041f182c000411b41014100410010001a2001410c460c01"
"0b418c83c000412341014100410010001a41000b21090240200041f0006a410c41a582c000410c1004410146044041"
"af83c000412341014100410010001a0c010b4100210941d283c000412c41014100410010001a0b024041a582c00041"
"0c200041f0006a410c1004410246044041fe83c000412341014100410010001a0c010b4100210941a184c000412c41"
"014100410010001a0b41cd84c000412041014100410010001a200041e8006a418b82c0002800003602002000418382"
"c000290000370360410921040340200041e0006a2201410c418382c000410c2001410c410010051a200441016b2204"
"0d000b200041f8006a410036020020004200370370420a200041f0006a410c41001001410c46220a45044041ed84c0"
"00411741014100410010001a0b0240200041f0006a410c200041e0006a410c1004450440418485c000411441014100"
"410010001a0c010b4100210a419885c000411641014100410010001a0b410b21040340200041e0006a2201410c4183"
"82c000410c2001410c410010061a200441016b22040d000b02402001410c41a582c000410c100445044041ae85c000"
"411941014100410010001a0c010b4100210a41c785c000411b41014100410010001a0b41e285c00041234101410041"
"0010001a200041c8006a410036020020004200370340420a200041406b410c410010011a200041d8006a418b82c000"
"2800003602002000418382c000290000370350410621040340200041d0006a2201410c200041406b410c2001410c41"
"0010071a200441016b22040d000b200041e8006a41003602002000420037036042c0843d200041e0006a2202410c41"
"0010011a02402002410c2001410c10042201450440418586c000411941014100410010001a0c010b419e86c000411b"
"41014100410010001a0b200145210c410721040340200041d0006a2201410c200041406b410c2001410c410010081a"
"200441016b22040d000b200041f8006a410036020020004200370370417f4201200041f0006a2202410c410010031a"
"02402001410c2002410c100445044041b986c000411741014100410010001a0c010b41d086c0004119410141004100"
"10001a4100210c0b41e986c000411741014100410010001a200041d8006a2202410036020020004200370350418382"
"c000410c4103200041d0006a2204410c410010091a418087c00041122004101341a582c000410c41062004410c4100"
"10091a419287c000411820041013200041e8006a22064100360200200042003703604209200041e0006a2203410c41"
"0010011a2003410c41022004410c410010091a41aa87c0004114200410132003410c41002004410c410010091a41be"
"87c000411720041013200041f8006a22014100360200200042003703704200200041f0006a2205410c410010011a20"
"05410c41022004410c410010091a41d587c00041142004101341e987c00041382005410c41002004410c41001009ac"
"100a1a41a188c000411841014100410010001a200241003602002000420037035042092004410c410010011a200641"
"00360200200042003703602004410c41022003410c4100100b1a41b988c0004112200310132004410c41032003410c"
"4100100b1a41cb88c000411220031013200141003602002000420037037042c0843d2005410c410010011a2005410c"
"41032003410c4100100b1a41dd88c0004118200310132005410c41062003410c4100100b1a41f588c000411c200310"
"13419189c000411741014100410010001a200641003602002000420037036042c0843d2003410c410010011a200141"
"00360200200042003703702003410c2005410c4100100c1a41a889c00041142005101341bc89c000411a4101410041"
"0010001a2001410036020020004200370370418382c000410c41a582c000410c2005410c410010071a024041a582c0"
"00410c2005410c1004220145044041d689c000411641014100410010001a0c010b41ec89c000411841014100410010"
"001a0b41a582c000410c41a582c000410c200041f0006a2202410c410010071a0240418382c000410c2002410c1004"
"450440200145210d41848ac000411741014100410010001a0c010b419b8ac000411941014100410010001a0b41b48a"
"c000411a41014100410010001a200041e8006a410036020020004200370360200041f8006a41003602002000420037"
"0370420a200041f0006a2202410c410010011a418382c000410c2002410c200041e0006a2201410c410010081a41ce"
"8ac000411920011013418382c000410c2001410c2001410c410010081a41e78ac000410f2001101302402002410c20"
"01410c1004220e45044041f68ac000411441014100410010001a0c010b418a8bc000411641014100410010001a0b41"
"00210141a08bc000411a41014100410010001a200042003703400240418382c000410c200041406b41084100100d22"
"0641084604402000290340220f42015104404101210141ba8bc000411741014100410010001a0c020b41d18bc00041"
"1941014100410010001a41ea8bc0004108200f100a1a0c010b41f28bc000412441014100410010001a41968cc00041"
"0f2006ac100a1a0b41002104024041a582c000410c200041406b41084100100d220641084604402000290340220f42"
"7f51044041a58cc000411841014100410010001a200121040c020b41bd8cc000411a41014100410010001a41ea8bc0"
"004108200f100a1a0c010b41d78cc000412541014100410010001a41968cc000410f2006ac100a1a0b410021012000"
"41d8006a41003602002000420037035042ffffffffffffffffff00200041d0006a2202410c410010011a0240200241"
"0c200041406b41084100100d220641084604402000290340220f42ffffffffffffffffff0051044041fc8cc000411e"
"41014100410010001a200421010c020b419a8dc000412041014100410010001a41ba8dc000410d42ffffffffffffff"
"ffff00100a1a41ea8bc0004108200f100a1a0c010b41c78dc000412b41014100410010001a41968cc000410f2006ac"
"100a1a0b41002106200041e8006a4100360200200042003703604200200041e0006a2202410c410010011a02402002"
"410c200041406b41084100100d220241084604402000290340220f50044041f28dc000411741014100410010001a20"
"0121060c020b41898ec000411941014100410010001a41ea8bc0004108200f100a1a0c010b41a28ec0004124410141"
"00410010001a41968cc000410f2002ac100a1a0b41002104200041f8006a410036020020004200370370417f420120"
"0041f0006a2201410c410010031a02402001410c200041406b41084100100d220141084604402000290340220f5004"
"4041c68ec000412541014100410010001a200621040c020b41eb8ec000412741014100410010001a41ea8bc0004108"
"200f100a1a0c010b41928fc000413241014100410010001a41968cc000410f2001ac100a1a0b0240200041f0006a41"
"0c200041406b41084101100d220141084604402000290340220f50044041c48fc000412741014100410010001a0c02"
"0b4100210441eb8fc000412941014100410010001a41ea8bc0004108200f100a1a0c010b41002104419490c0004134"
"41014100410010001a41968cc000410f2001ac100a1a0b4100210141c890c000412c41014100410010001a20004200"
"370320200041003602040240418382c000410c200041206a4108200041046a4104100e2206410c4604402000280204"
"2206416e462000290320220f42808090bbbad6adf00d5171450440419d91c000412b41014100410010001a41c891c0"
"00412f200f100a1a41f791c000411f2006ac100a1a0c020b4101210141f490c000412941014100410010001a0c010b"
"419692c000413641014100410010001a41968cc000410f2006ac100a1a0b2000420037033041002106200041003602"
"08024041a582c000410c200041306a4108200041086a4104100e2202410c46044020002802082202416e4620002903"
"30220f428080f0c4c5a9d28f72517145044041f692c000412c41014100410010001a41a293c0004130200f100a1a41"
"f791c000411f2002ac100a1a0c020b41cc92c000412a41014100410010001a200121060c010b41d293c00041374101"
"4100410010001a41968cc000410f2002ac100a1a0b41002101200041e8006a410036020020004200370360420a2000"
"41e0006a2202410c410010011a200042003703402000410036020c02402002410c200041406b41082000410c6a4104"
"100e2202410c460440200028020c2202416f462000290340220f42808090bbbad6adf00d517145044041b394c00041"
"2c41014100410010001a41c891c000412f200f100a1a41df94c000411f2002ac100a1a0c020b418994c000412a4101"
"4100410010001a200621010c010b41fe94c000413741014100410010001a41968cc000410f2002ac100a1a0b410021"
"06200041f8006a4100360200200042003703704200200041f0006a2202410c410010011a2000420037035020004100"
"36021002402002410c200041d0006a4108200041106a4104100e2202410c4604402000290350220f50200028021022"
"02418080808078467145044041de95c000412b41014100410010001a418996c000411d200f100a1a41a696c0004127"
"2002ac100a1a0c020b41b595c000412941014100410010001a200121060c010b41cd96c00041364101410041001000"
"1a41968cc000410f2002ac100a1a0b4100210141bc89c000411a41014100410010001a200041c8006a410036020020"
"0042003703400240418382c000410c200041406b2203410c100f2202410c460440200341a582c00010150440418397"
"c000412b41014100410010001a0c020b4101210141ae97c000411741014100410010001a0c010b41c597c000412441"
"014100410010001a41968cc000410f2002ac100a1a0b41002102200041d8006a410036020020004200370350024041"
"a582c000410c200041d0006a2205410c100f2203410c4604402005418382c0001015044041e997c000412c41014100"
"410010001a0c020b419598c000411841014100410010001a200121020c010b41ad98c000412541014100410010001a"
"41968cc000410f2003ac100a1a0b200041e8006a4100360200200042003703604200200041e0006a2203410c410010"
"011a200041f8006a41003602002000420037037002402003410c200041f0006a2205410c100f2201410c4604402005"
"20031015044041d298c000412b41014100410010001a0c020b41fd98c000411741014100410010001a2002210b0c01"
"0b419499c000412441014100410010001a41968cc000410f2001ac100a1a0b4100210141b899c00041174101410041"
"0010001a200041186a4100360200200042003703100240418382c000410c200041106a2203410c10102202410c4604"
"402003418382c0001015044041cf99c000412841014100410010001a0c020b4101210141f799c00041144101410041"
"0010001a0c010b418b9ac000412141014100410010001a41968cc000410f2002ac100a1a0b41002102200041286a41"
"0036020020004200370320024041a582c000410c200041206a2205410c10102203410c4604402005418382c0001015"
"044041ac9ac000412941014100410010001a0c020b41d59ac000411541014100410010001a200121020c010b41ea9a"
"c000412241014100410010001a41968cc000410f2003ac100a1a0b41002101200041386a4100360200200042003703"
"304200200041306a2205410c410010011a200041c8006a41003602002000420037034002402005410c200041406b22"
"07410c10102203410c4604402007200510150440418c9bc000412841014100410010001a0c020b41b49bc000411441"
"014100410010001a200221010c010b41c89bc000412141014100410010001a41968cc000410f2003ac100a1a0b4100"
"2102200041d8006a4100360200200042003703504276200041d0006a2203410c410010011a200041e8006a41003602"
"0020004200370360420a200041e0006a2205410c410010011a200041f8006a41003602002000420037037002402003"
"410c200041f0006a2207410c10102203410c460440200720051015044041e99bc000412a41014100410010001a0c02"
"0b41939cc000411641014100410010001a200121020c010b41a99cc000412341014100410010001a41968cc000410f"
"2003ac100a1a0b4100210141cc9cc000412141014100410010001a200042c0808080d0a0fdf000370050200041f800"
"6a41003602002000420037037002400240200041d0006a4108200041f0006a2205410c410010112203410c46044041"
"ed9cc000412220051013200042003703602005410c200041e0006a41084100100d22034108470d012000290360220f"
"4280c2d72f51044041012101418f9dc000411d41014100410010001a0c030b41ac9dc000411f41014100410010001a"
"41cb9dc000411c200f100a1a0c020b419b9ec000411f41014100410010001a41ba9ec00041102003ac100a1a0c010b"
"41e79dc000413441014100410010001a41968cc000410f2003ac100a1a0b4100210341ca9ec0004121410141004100"
"10001a200041ffffff8f7f36006820004281eceedce494ccf9c000370060200041f8006a4100360200200042003703"
"7002400240200041e0006a410c200041f0006a2207410c410010122205410c46044041eb9ec000411c200710132000"
"42003703502007410c200041d0006a41084100100d22054108470d012000290350220f42fb00510440410121034187"
"9fc000411b41014100410010001a0c030b41a29fc000411d41014100410010001a41bf9fc0004116200f100a1a0c02"
"0b4187a0c000411d41014100410010001a41ba9ec00041102005ac100a1a0c010b41d59fc000413241014100410010"
"001a41968cc000410f2005ac100a1a0b410021050240418382c000410c200041f0006a2207410c41001012410c4604"
"4041a4a0c000411a200710132007410c418382c000410c100445044041bea0c000412041014100410010001a200321"
"050c020b41dea0c000412241014100410010001a0c010b4180a1c000412041014100410010001a0b20004180016a24"
"00200e452008200971200a71200c71200d71200471200671200b71200271200171200571710b4201047f410c210202"
"40034020002d0000220320012d00002204460440200041016a2100200141016a2101200241016b22020d010c020b0b"
"200320046b21050b20050b0baa210100418080c0000ba02120200a24242420746573745f666c6f61745f66726f6d5f"
"7761736d202424242020666c6f61742066726f6d206936342031323330303a2020666c6f61742066726f6d20693634"
"203132333030206173204845583a2020666c6f61742066726f6d206936342031323330303a206661696c6564202066"
"6c6f61742066726f6d207536342031323330303a2020666c6f61742066726f6d207536342031323330303a20666169"
"6c65642020666c6f61742066726f6d2065787020322c206d616e7469737361203132333a2020666c6f61742066726f"
"6d2065787020322c206d616e746973736120333a206661696c65642020666c6f61742066726f6d20636f6e73742031"
"3a0de0b6b3a7640000ffffffee2020666c6f61742066726f6d20636f6e7374202d313af21f494c589c0000ffffffee"
"0a24242420746573745f666c6f61745f636f6d70617265202424242020666c6f61742066726f6d20313a2020666c6f"
"61742066726f6d20313a206661696c65642020666c6f61742066726f6d2031203d3d20464c4f41545f4f4e45202066"
"6c6f61742066726f6d203120213d20464c4f41545f4f4e452c206661696c65642020666c6f61742066726f6d203120"
"3e20464c4f41545f4e454741544956455f4f4e452020666c6f61742066726f6d203120213e20464c4f41545f4e4547"
"41544956455f4f4e452c206661696c65642020464c4f41545f4e454741544956455f4f4e45203c20666c6f61742066"
"726f6d20312020464c4f41545f4e454741544956455f4f4e4520213c20666c6f61742066726f6d20312c206661696c"
"65640a24242420746573745f666c6f61745f6164645f7375627472616374202424242020666c6f61742066726f6d20"
"31303a206661696c656420207265706561746564206164643a20676f6f6420207265706561746564206164643a2066"
"61696c6564202072657065617465642073756274726163743a20676f6f642020726570656174656420737562747261"
"63743a206661696c65640a24242420746573745f666c6f61745f6d756c7469706c795f646976696465202424242020"
"7265706561746564206d756c7469706c793a20676f6f6420207265706561746564206d756c7469706c793a20666169"
"6c656420207265706561746564206469766964653a20676f6f6420207265706561746564206469766964653a206661"
"696c65640a24242420746573745f666c6f61745f706f77202424242020666c6f61742063756265206f6620313a2020"
"666c6f61742036746820706f776572206f66202d313a2020666c6f617420737175617265206f6620393a2020666c6f"
"61742030746820706f776572206f6620393a2020666c6f617420737175617265206f6620303a2020666c6f61742030"
"746820706f776572206f6620302028657870656374696e6720494e56414c49445f504152414d53206572726f72293a"
"0a24242420746573745f666c6f61745f726f6f74202424242020666c6f61742073717274206f6620393a2020666c6f"
"61742063627274206f6620393a2020666c6f61742063627274206f6620313030303030303a2020666c6f6174203674"
"6820726f6f74206f6620313030303030303a0a24242420746573745f666c6f61745f6c6f672024242420206c6f675f"
"3130206f6620313030303030303a0a24242420746573745f666c6f61745f6e65676174652024242420206e65676174"
"6520636f6e737420313a20676f6f6420206e656761746520636f6e737420313a206661696c656420206e6567617465"
"20636f6e7374202d313a20676f6f6420206e656761746520636f6e7374202d313a206661696c65640a242424207465"
"73745f666c6f61745f696e76657274202424242020696e76657274206120666c6f61742066726f6d2031303a202069"
"6e7665727420616761696e3a2020696e766572742074776963653a20676f6f642020696e766572742074776963653a"
"206661696c65640a24242420746573745f666c6f61745f746f5f696e74202424242020666c6f61745f746f5f696e74"
"2831293a20676f6f642020666c6f61745f746f5f696e742831293a206661696c656420202020676f743a2020666c6f"
"61745f746f5f696e742831293a206661696c65642077697468206572726f72202020206572726f7220636f64653a20"
"20666c6f61745f746f5f696e74282d31293a20676f6f642020666c6f61745f746f5f696e74282d31293a206661696c"
"65642020666c6f61745f746f5f696e74282d31293a206661696c65642077697468206572726f722020666c6f61745f"
"746f5f696e74286936343a3a4d4158293a20676f6f642020666c6f61745f746f5f696e74286936343a3a4d4158293a"
"206661696c65642020202065787065637465643a2020666c6f61745f746f5f696e74286936343a3a4d4158293a2066"
"61696c65642077697468206572726f722020666c6f61745f746f5f696e742830293a20676f6f642020666c6f61745f"
"746f5f696e742830293a206661696c65642020666c6f61745f746f5f696e742830293a206661696c65642077697468"
"206572726f722020666c6f61745f746f5f696e7428302e312c20746f5f6e656172657374293a20676f6f642020666c"
"6f61745f746f5f696e7428302e312c20746f5f6e656172657374293a206661696c65642020666c6f61745f746f5f69"
"6e7428302e312c20746f5f6e656172657374293a206661696c65642077697468206572726f722020666c6f61745f74"
"6f5f696e7428302e312c20746f77617264735f7a65726f293a20676f6f642020666c6f61745f746f5f696e7428302e"
"312c20746f77617264735f7a65726f293a206661696c65642020666c6f61745f746f5f696e7428302e312c20746f77"
"617264735f7a65726f293a206661696c65642077697468206572726f720a24242420746573745f666c6f61745f746f"
"5f6d616e74697373615f616e645f6578706f6e656e74202424242020666c6f61745f746f5f6d616e74697373615f61"
"6e645f6578706f6e656e742831293a20676f6f642020666c6f61745f746f5f6d616e74697373615f616e645f657870"
"6f6e656e742831293a206661696c6564202020206578706563746564206d616e746973736120313030303030303030"
"303030303030303030302c20676f743a202020206578706563746564206578706f6e656e74202d31382c20676f743a"
"2020666c6f61745f746f5f6d616e74697373615f616e645f6578706f6e656e742831293a206661696c656420776974"
"68206572726f722020666c6f61745f746f5f6d616e74697373615f616e645f6578706f6e656e74282d31293a20676f"
"6f642020666c6f61745f746f5f6d616e74697373615f616e645f6578706f6e656e74282d31293a206661696c656420"
"2020206578706563746564206d616e7469737361202d313030303030303030303030303030303030302c20676f743a"
"2020666c6f61745f746f5f6d616e74697373615f616e645f6578706f6e656e74282d31293a206661696c6564207769"
"7468206572726f722020666c6f61745f746f5f6d616e74697373615f616e645f6578706f6e656e74283130293a2067"
"6f6f642020666c6f61745f746f5f6d616e74697373615f616e645f6578706f6e656e74283130293a206661696c6564"
"202020206578706563746564206578706f6e656e74202d31372c20676f743a2020666c6f61745f746f5f6d616e7469"
"7373615f616e645f6578706f6e656e74283130293a206661696c65642077697468206572726f722020666c6f61745f"
"746f5f6d616e74697373615f616e645f6578706f6e656e742830293a20676f6f642020666c6f61745f746f5f6d616e"
"74697373615f616e645f6578706f6e656e742830293a206661696c6564202020206578706563746564206d616e7469"
"73736120302c20676f743a202020206578706563746564206578706f6e656e74202d323134373438333634382c2067"
"6f743a2020666c6f61745f746f5f6d616e74697373615f616e645f6578706f6e656e742830293a206661696c656420"
"77697468206572726f722020666c6f61745f6e65676174652831293a206661696c6564202d20726573756c74206d69"
"736d617463682020666c6f61745f6e65676174652831293a20676f6f642020666c6f61745f6e65676174652831293a"
"206661696c65642077697468206572726f722020666c6f61745f6e6567617465282d31293a206661696c6564202d20"
"726573756c74206d69736d617463682020666c6f61745f6e6567617465282d31293a20676f6f642020666c6f61745f"
"6e6567617465282d31293a206661696c65642077697468206572726f722020666c6f61745f6e65676174652830293a"
"206661696c6564202d20726573756c74206d69736d617463682020666c6f61745f6e65676174652830293a20676f6f"
"642020666c6f61745f6e65676174652830293a206661696c65642077697468206572726f720a24242420746573745f"
"666c6f61745f616273202424242020666c6f61745f6162732831293a206661696c6564202d20726573756c74206d69"
"736d617463682020666c6f61745f6162732831293a20676f6f642020666c6f61745f6162732831293a206661696c65"
"642077697468206572726f722020666c6f61745f616273282d31293a206661696c6564202d20726573756c74206d69"
"736d617463682020666c6f61745f616273282d31293a20676f6f642020666c6f61745f616273282d31293a20666169"
"6c65642077697468206572726f722020666c6f61745f6162732830293a206661696c6564202d20726573756c74206d"
"69736d617463682020666c6f61745f6162732830293a20676f6f642020666c6f61745f6162732830293a206661696c"
"65642077697468206572726f722020666c6f61745f616273282d3130293a206661696c6564202d20726573756c7420"
"6d69736d617463682020666c6f61745f616273282d3130293a20676f6f642020666c6f61745f616273282d3130293a"
"206661696c65642077697468206572726f720a24242420746573745f666c6f61745f66726f6d5f7374616d6f756e74"
"202424242020666c6f61742066726f6d2058525020616d6f756e74202831303020585250293a202058525020616d6f"
"756e7420636f6e76657273696f6e3a20676f6f64202058525020616d6f756e7420636f6e76657273696f6e3a206661"
"696c6564202020206578706563746564203130303030303030302c20676f743a202058525020616d6f756e7420636f"
"6e76657273696f6e3a206661696c6564202d20666c6f61745f746f5f696e74206572726f722020666c6f6174206672"
"6f6d2058525020616d6f756e743a206661696c656420202020726573756c745f73697a653a0a24242420746573745f"
"666c6f61745f66726f6d5f73746e756d626572202424242020666c6f61742066726f6d2053544e756d626572202831"
"3233293a202053544e756d62657220636f6e76657273696f6e3a20676f6f64202053544e756d62657220636f6e7665"
"7273696f6e3a206661696c6564202020206578706563746564203132332c20676f743a202053544e756d6265722063"
"6f6e76657273696f6e3a206661696c6564202d20666c6f61745f746f5f696e74206572726f722020666c6f61742066"
"726f6d2053544e756d6265723a206661696c65642020666c6f61742066726f6d2053544e756d626572202831293a20"
"2053544e756d626572283129203d3d20464c4f41545f4f4e453a20676f6f64202053544e756d626572283129203d3d"
"20464c4f41545f4f4e453a206661696c65642020666c6f61742066726f6d2053544e756d6265722831293a20666169"
"6c6564004d0970726f64756365727302086c616e6775616765010452757374000c70726f6365737365642d62790105"
"72757374631d312e38392e30202832393438333838336520323032352d30382d303429002c0f7461726765745f6665"
"617475726573022b0f6d757461626c652d676c6f62616c732b087369676e2d657874";
extern std::string const float0Hex =
"0061736d0100000001290560057f7f7f7f7f017f60047e7f7f7f017f60077f7f7f7f7f7f7f017f60047f7f7f7f017f"
"6000017f025f0408686f73745f6c6962057472616365000008686f73745f6c69620e666c6f61745f66726f6d5f696e"
"74000108686f73745f6c69620e666c6f61745f7375627472616374000208686f73745f6c69620d666c6f61745f636f"
"6d7061726500030302010405030100110619037f01418080c0000b7f00419281c0000b7f0041a081c0000b072e0406"
"6d656d6f727902000666696e69736800040a5f5f646174615f656e6403010b5f5f686561705f6261736503020abe02"
"01bb0201017f23808080800041206b2200248080808000418080c0800041154100410041001080808080001a200042"
"003703084200200041086a410841001081808080001a20004200370310420a200041106a410841001081808080001a"
"200042003703180240200041106a4108200041106a4108200041186a410841001082808080004108460d00419580c0"
"800041154100410041001080808080001a0b02400240200041086a4108200041186a41081083808080000d0041aa80"
"c0800041174100410041001080808080001a0c010b41c180c0800041164100410041001080808080001a0b02400240"
"200041086a410841d780c0800041081083808080000d0041df80c08000411a4100410041001080808080001a0c010b"
"41f980c0800041194100410041001080808080001a0b200041206a24808080800041010b0b9c010100418080c0000b"
"92010a24242420746573745f666c6f61745f30202424242020666c6f61742031302d31303a206661696c6564202066"
"6c6f6174203020636f6d706172653a20676f6f642020666c6f6174203020636f6d706172653a206261648000000000"
"0000002020464c4f41545f5a45524f20636f6d706172653a20676f6f642020464c4f41545f5a45524f20636f6d7061"
"72653a20626164009502046e616d65001110666c6f61745f74657374732e7761736d01da0105002b5f5a4e38787270"
"6c5f73746434686f7374357472616365313768616338383262323664656162656436364501355f5a4e387872706c5f"
"73746434686f73743134666c6f61745f66726f6d5f696e74313768303234306638653361383964313939654502355f"
"5a4e387872706c5f73746434686f73743134666c6f61745f7375627472616374313768643634306331353233343534"
"323935634503345f5a4e387872706c5f73746434686f73743133666c6f61745f636f6d706172653137683663386465"
"656231323864393638386645040666696e697368071201000f5f5f737461636b5f706f696e746572090a0100072e72"
"6f64617461004d0970726f64756365727302086c616e6775616765010452757374000c70726f6365737365642d6279"
"010572757374631d312e38392e30202832393438333838336520323032352d30382d3034290094010f746172676574"
"5f6665617475726573082b0b62756c6b2d6d656d6f72792b0f62756c6b2d6d656d6f72792d6f70742b1663616c6c2d"
"696e6469726563742d6f7665726c6f6e672b0a6d756c746976616c75652b0f6d757461626c652d676c6f62616c732"
"b136e6f6e7472617070696e672d6670746f696e742b0f7265666572656e63652d74797065732b087369676e2d65787"
"4";
"6d7061726500030302010405030100110619037f01418080c0000b7f00419681c0000b7f0041a081c0000b072e0406"
"6d656d6f727902000666696e69736800040a5f5f646174615f656e6403010b5f5f686561705f6261736503020ad302"
"01d00201017f23808080800041206b2200248080808000418080c0800041154101410041001080808080001a200041"
"086a410036020020004200370300200041106a41086a410036020020004200370310024002400240420a2000410c41"
"00108180808000410c470d002000410c2000410c200041106a410c4100108280808000410c470d0102400240200041"
"106a410c200041106a410c1083808080000d00419580c0800041174101410041001080808080001a0c010b41ac80c0"
"800041164101410041001080808080001a0b0240200041106a410c41c280c08000410c1083808080000d0041ce80c0"
"8000411a4101410041001080808080001a0c030b41e880c0800041194101410041001080808080001a0c020b418181"
"c0800041154101410041001080808080001a0c010b418181c0800041154101410041001080808080001a0b20004120"
"6a24808080800041010b0ba0010100418080c0000b96010a24242420746573745f666c6f61745f3020242424202066"
"6c6f6174203020636f6d706172653a20676f6f642020666c6f6174203020636f6d706172653a206261640000000000"
"000000800000002020464c4f41545f5a45524f20636f6d706172653a20676f6f642020464c4f41745f5a45524f2063"
"6f6d706172653a206261642020666c6f61742031302d31303a206661696c6564009503046e616d65000d0c666c6f61"
"745f302e7761736d01de0205004c5f5a4e31367872706c5f7761736d5f7374646c696234686f73743232686f73745f"
"646566696e65645f66756e6374696f6e73357472616365313768653738323066313637383330383338364501565f5a"
"4e31367872706c5f7761736d5f7374646c696234686f73743232686f73745f646566696e65645f66756e6374696f6e"
"733134666c6f61745f66726f6d5f696e74313768646463636262643266613366663431634502565f5a4e3136787270"
"6c5f7761736d5f7374646c696234686f73743232686f73745f646566696e65645f66756e6374696f6e733134666c6f"
"61745f7375627472616374313768313765643838343131303333663437624503555f5a4e31367872706c5f7761736d"
"5f7374646c696234686f73743232686f73745f646566696e65645f66756e6374696f6e733133666c6f61745f636f6d"
"706172653137683835393637633834333363613334623045040666696e697368071201000f5f5f737461636b5f706f"
"696e746572090a0100072e726f64617461004d0970726f64756365727302086c616e6775616765010452757374000c"
"70726f6365737365642d6279010572757374631d312e38392e30202832393438333838336520323032352d30382d30"
"34290094010f7461726765745f6665617475726573082b0b62756c6b2d6d656d6f72792b0f62756c6b2d6d656d6f72"
"792d6f70742b1663616c6c2d696e6469726563742d6f7665726c6f6e672b0a6d756c746976616c75652b0f6d757461"
"626c652d676c6f62616c732b136e6f6e7472617070696e672d6670746f696e742b0f7265666572656e63652d747970"
"65732b087369676e2d657874";
extern std::string const disabledFloatHex =
"0061736d010000000108026000006000017f03030200010503010002063e0a7f004180080b7f004180080b7f004180"

View File

@@ -0,0 +1,171 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bs58"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
dependencies = [
"tinyvec",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "float_0"
version = "0.0.1"
dependencies = [
"xrpl-wasm-stdlib",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "libc"
version = "0.2.183"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tinyvec"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "typenum"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "xrpl-address-macro"
version = "0.7.1"
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?rev=1e5d096f46742ef7fcf1cb6f28a2526a72ed59d8#1e5d096f46742ef7fcf1cb6f28a2526a72ed59d8"
dependencies = [
"bs58",
"quote",
"sha2",
"syn",
]
[[package]]
name = "xrpl-wasm-stdlib"
version = "0.7.1"
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?rev=1e5d096f46742ef7fcf1cb6f28a2526a72ed59d8#1e5d096f46742ef7fcf1cb6f28a2526a72ed59d8"
dependencies = [
"xrpl-address-macro",
]

View File

@@ -0,0 +1,21 @@
[package]
name = "float_0"
version = "0.0.1"
edition = "2024"
# This empty workspace definition keeps this project independent of the parent workspace
[workspace]
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true
opt-level = 's'
panic = "abort"
[dependencies]
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", rev = "1e5d096f46742ef7fcf1cb6f28a2526a72ed59d8" }
[profile.dev]
panic = "abort"

View File

@@ -0,0 +1,57 @@
#![cfg_attr(target_arch = "wasm32", no_std)]
use xrpl_std::host::trace::trace;
use xrpl_std::host::{float_compare, float_from_int, float_subtract, FLOAT_ROUNDING_MODES_TO_NEAREST};
// Float size constant (8 bytes mantissa + 4 bytes exponent)
const FLOAT_SIZE: usize = 12;
// FLOAT_ZERO constant
const FLOAT_ZERO: [u8; FLOAT_SIZE] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00];
#[unsafe(no_mangle)]
pub extern "C" fn finish() -> i32 {
let _ = trace("\n$$$ test_float_0 $$$");
// Test: 10 - 10 should equal 0
let mut f10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
let mut f_result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
// Create float from 10
if FLOAT_SIZE as i32 != unsafe { float_from_int(10, f10.as_mut_ptr(), FLOAT_SIZE, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
let _ = trace(" float 10-10: failed");
return 1;
}
// Subtract: 10 - 10 = 0
if FLOAT_SIZE as i32 != unsafe {
float_subtract(
f10.as_ptr(),
FLOAT_SIZE,
f10.as_ptr(),
FLOAT_SIZE,
f_result.as_mut_ptr(),
FLOAT_SIZE,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
} {
let _ = trace(" float 10-10: failed");
return 1;
}
// Compare result with zero
if 0 == unsafe { float_compare(f_result.as_ptr(), FLOAT_SIZE, f_result.as_ptr(), FLOAT_SIZE) } {
let _ = trace(" float 0 compare: good");
} else {
let _ = trace(" float 0 compare: bad");
}
// Compare result with FLOAT_ZERO constant
if 0 == unsafe { float_compare(f_result.as_ptr(), FLOAT_SIZE, FLOAT_ZERO.as_ptr(), FLOAT_SIZE) } {
let _ = trace(" FLOAT_ZERO compare: good");
} else {
let _ = trace(" FLOAT_ZERO compare: bad");
}
1
}

File diff suppressed because it is too large Load Diff

View File

@@ -1568,13 +1568,15 @@ public:
{Number{1'000'000'000'000'000ll}, Number{15}},
{Number{5625, -4}, Number{-2'498'774'732'165'998, -16}}});
auto const cLarge = std::to_array<Case>(
{{Number{false, Number::maxMantissa() - 9, -1, Number::normalized{}},
Number{false, 1'746'901'684'478'673'451ll, -17, Number::normalized{}}},
{Number{false, Number::maxMantissa() - 9, 0, Number::normalized{}},
Number{false, 1'846'901'684'478'673'451ll, -17, Number::normalized{}}},
{Number{Number::maxRep},
Number{false, 1'861'728'612'932'620'011ll, -17, Number::normalized{}}}});
auto const cLarge = std::to_array<Case>({
{Number{Number::maxMantissa() - 9, -1, Number::normalized{}},
Number{1'799'999'999'999'999'999ll, -17}},
{Number{Number::maxMantissa() - 9, 0, Number::normalized{}},
Number{1'899'999'999'999'999'999ll, -17}},
{Number{Number::maxRep, 0, Number::normalized{}},
Number{1'896'488'972'683'081'529ll, -17}},
{Number{999'999'999'999'999'999ll}, Number{1'799'999'999'999'999'999, -17}},
});
if (Number::getMantissaScale() == MantissaRange::small)
{