mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 00:36:48 +00:00
Refactoring float hostfunctions (#7053)
This commit is contained in:
@@ -381,9 +381,6 @@ 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
|
||||
@@ -732,10 +729,6 @@ abs(Number x) noexcept
|
||||
Number
|
||||
power(Number const& f, unsigned n);
|
||||
|
||||
// logarithm with base 10
|
||||
Number
|
||||
log10(Number const& value, int iterations = 50);
|
||||
|
||||
// Returns f^(1/d)
|
||||
// Uses Newton–Raphson iterations until the result stops changing
|
||||
// to find the root of the polynomial g(x) = x^d - f
|
||||
|
||||
@@ -66,16 +66,10 @@ Expected<int64_t, HostFunctionError>
|
||||
floatToIntImpl(Slice const& x, int32_t mode);
|
||||
|
||||
Expected<FloatPair, HostFunctionError>
|
||||
floatToMantissaAndExponentImpl(Slice const& x);
|
||||
floatToMantExpImpl(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);
|
||||
floatFromMantExpImpl(int64_t mantissa, int32_t exponent, int32_t mode);
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
floatCompareImpl(Slice const& x, Slice const& y);
|
||||
@@ -98,9 +92,6 @@ floatRootImpl(Slice const& x, int32_t n, int32_t mode);
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatPowerImpl(Slice const& x, int32_t n, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatLogImpl(Slice const& x, int32_t mode);
|
||||
|
||||
} // namespace wasm_float
|
||||
|
||||
// Intended to work only through wasm runtime. Don't call them directly, except with unit tests
|
||||
@@ -480,25 +471,13 @@ struct HostFunctions
|
||||
}
|
||||
|
||||
virtual Expected<FloatPair, HostFunctionError>
|
||||
floatToMantissaAndExponent(Slice const& x) const
|
||||
floatToMantExp(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
|
||||
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
@@ -545,12 +524,6 @@ struct HostFunctions
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatLog(Slice const& x, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
|
||||
virtual ~HostFunctions() = default;
|
||||
// LCOV_EXCL_STOP
|
||||
};
|
||||
|
||||
@@ -266,16 +266,10 @@ public:
|
||||
floatToInt(Slice const& x, int32_t mode) const override;
|
||||
|
||||
Expected<FloatPair, HostFunctionError>
|
||||
floatToMantissaAndExponent(Slice const& x) const override;
|
||||
floatToMantExp(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;
|
||||
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
floatCompare(Slice const& x, Slice const& y) const override;
|
||||
@@ -297,9 +291,6 @@ public:
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatPower(Slice const& x, int32_t n, int32_t mode) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatLog(Slice const& x, int32_t mode) const override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -276,22 +276,13 @@ using floatToInt_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int
|
||||
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);
|
||||
using floatToMantExp_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);
|
||||
floatToMantExp_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);
|
||||
using floatFromMantExp_proto = int32_t(int64_t, int32_t, uint8_t*, int32_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);
|
||||
floatFromMantExp_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||
|
||||
using floatCompare_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t*
|
||||
@@ -325,8 +316,4 @@ using floatPower_proto = int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int
|
||||
wasm_trap_t*
|
||||
floatPower_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||
|
||||
using floatLog_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t*
|
||||
floatLog_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -52,7 +52,7 @@ enum WasmTypes { WT_I32, WT_I64 };
|
||||
|
||||
struct WasmImportFunc
|
||||
{
|
||||
std::string name;
|
||||
std::string_view name;
|
||||
std::optional<WasmTypes> result;
|
||||
std::vector<WasmTypes> params;
|
||||
// void* udata = nullptr;
|
||||
@@ -62,11 +62,12 @@ struct WasmImportFunc
|
||||
};
|
||||
|
||||
typedef std::pair<void*, WasmImportFunc> WasmUserData;
|
||||
typedef std::vector<WasmUserData> ImportVec;
|
||||
typedef std::unordered_map<std::string_view, WasmUserData> ImportVec;
|
||||
|
||||
#define WASM_IMPORT_FUNC(v, f, ...) \
|
||||
WasmImpFunc<f##_proto>(v, #f, reinterpret_cast<void*>(&f##_wrap), ##__VA_ARGS__)
|
||||
|
||||
// n - string literal name, must have static lifetime
|
||||
#define WASM_IMPORT_FUNC2(v, f, n, ...) \
|
||||
WasmImpFunc<f##_proto>(v, n, reinterpret_cast<void*>(&f##_wrap), ##__VA_ARGS__)
|
||||
|
||||
@@ -123,6 +124,7 @@ WasmImpFuncHelper(WasmImportFunc& e)
|
||||
// WasmImpWrap(e, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// imp_name - string literal, must have static lifetime
|
||||
template <typename F>
|
||||
void
|
||||
WasmImpFunc(
|
||||
@@ -137,7 +139,7 @@ WasmImpFunc(
|
||||
e.wrap = f_wrap;
|
||||
e.gas = gas;
|
||||
WasmImpFuncHelper<F>(e);
|
||||
v.push_back(std::make_pair(data, std::move(e)));
|
||||
v.emplace(imp_name, std::make_pair(data, std::move(e)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -945,82 +945,6 @@ power(Number const& f, unsigned n)
|
||||
return r;
|
||||
}
|
||||
|
||||
// Series expansion method approximation of ln(x)
|
||||
static Number
|
||||
ln(Number const& x, int iterations = 50)
|
||||
{
|
||||
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)
|
||||
{
|
||||
throw std::runtime_error("Not a positive value");
|
||||
}
|
||||
if (x == 1)
|
||||
{
|
||||
return N0;
|
||||
}
|
||||
|
||||
int exponent = 0;
|
||||
Number mantissa = x;
|
||||
|
||||
while (mantissa >= N2)
|
||||
{
|
||||
mantissa /= 2;
|
||||
exponent += 1;
|
||||
}
|
||||
while (mantissa < N05)
|
||||
{
|
||||
mantissa *= 2;
|
||||
exponent -= 1;
|
||||
}
|
||||
|
||||
Number z = (mantissa - 1) / (mantissa + 1);
|
||||
Number const zz = z * z;
|
||||
Number sum;
|
||||
|
||||
for (int i = 1; i <= iterations; ++i)
|
||||
{
|
||||
sum = sum + z / ((2 * i) - 1);
|
||||
z = z * zz;
|
||||
}
|
||||
|
||||
return 2 * sum + exponent * LN2;
|
||||
}
|
||||
|
||||
Number
|
||||
log10(Number const& x, int iterations)
|
||||
{
|
||||
Number const N0(0);
|
||||
Number const LN10(2'302'585'092'994'045'684ll, -18);
|
||||
|
||||
if (x <= 0)
|
||||
{
|
||||
throw std::runtime_error("Not a positive value");
|
||||
}
|
||||
if (x == 1)
|
||||
{
|
||||
return N0;
|
||||
}
|
||||
|
||||
if (x <= Number(10))
|
||||
{
|
||||
auto const r = ln(x, iterations) / LN10;
|
||||
return r;
|
||||
}
|
||||
|
||||
// (1 <= normalX < 10)
|
||||
// x = normalX * 10^norm
|
||||
// ln(x) = ln(normalX * 10^norm) = ln(normalX) + norm * ln(10)
|
||||
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;
|
||||
return lgX;
|
||||
}
|
||||
|
||||
// Returns f^(1/d)
|
||||
// Uses Newton–Raphson iterations until the result stops changing
|
||||
// to find the non-negative root of the polynomial g(x) = x^d - f
|
||||
|
||||
@@ -259,7 +259,7 @@ floatToIntImpl(Slice const& x, int32_t mode)
|
||||
}
|
||||
|
||||
Expected<FloatPair, HostFunctionError>
|
||||
floatToMantissaAndExponentImpl(Slice const& x)
|
||||
floatToMantExpImpl(Slice const& x)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -282,55 +282,7 @@ floatToMantissaAndExponentImpl(Slice const& x)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSetImpl(int64_t mantissa, int32_t exponent, int32_t mode)
|
||||
floatFromMantExpImpl(int64_t mantissa, int32_t exponent, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -537,31 +489,6 @@ floatPowerImpl(Slice const& x, int32_t n, int32_t mode)
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatLogImpl(Slice const& x, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
detail::WasmNumber const xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
detail::WasmNumber const res(log10(xx));
|
||||
|
||||
return res.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
} // namespace wasm_float
|
||||
|
||||
// =========================================================
|
||||
@@ -599,27 +526,15 @@ WasmHostFunctionsImpl::floatToInt(Slice const& x, int32_t mode) const
|
||||
}
|
||||
|
||||
Expected<FloatPair, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatToMantissaAndExponent(Slice const& x) const
|
||||
WasmHostFunctionsImpl::floatToMantExp(Slice const& x) const
|
||||
{
|
||||
return wasm_float::floatToMantissaAndExponentImpl(x);
|
||||
return wasm_float::floatToMantExpImpl(x);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatNegate(Slice const& x) const
|
||||
WasmHostFunctionsImpl::floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) 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
|
||||
{
|
||||
return wasm_float::floatSetImpl(mantissa, exponent, mode);
|
||||
return wasm_float::floatFromMantExpImpl(mantissa, exponent, mode);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
@@ -664,10 +579,4 @@ WasmHostFunctionsImpl::floatPower(Slice const& x, int32_t n, int32_t mode) const
|
||||
return wasm_float::floatPowerImpl(x, n, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatLog(Slice const& x, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatLogImpl(x, mode);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -1769,7 +1769,7 @@ floatToInt_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatToMantissaAndExponent_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||
floatToMantExp_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
|
||||
@@ -1782,11 +1782,11 @@ floatToMantissaAndExponent_wrap(void* env, wasm_val_vec_t const* params, wasm_va
|
||||
return hfResult(results, x.error());
|
||||
|
||||
i = 2;
|
||||
return returnResult(runtime, params, results, hf->floatToMantissaAndExponent(*x), i);
|
||||
return returnResult(runtime, params, results, hf->floatToMantExp(*x), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatNegate_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||
floatFromMantExp_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
|
||||
@@ -1794,55 +1794,22 @@ floatNegate_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* result
|
||||
auto* runtime = reinterpret_cast<WasmRuntimeWrapper*>(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* runtime = reinterpret_cast<WasmRuntimeWrapper*>(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)
|
||||
{
|
||||
if (auto g = checkGas(env); !g)
|
||||
return g.error(); // LCOV_EXCL_LINE
|
||||
auto* hf = getHF(env);
|
||||
auto* runtime = reinterpret_cast<WasmRuntimeWrapper*>(hf->getRT());
|
||||
|
||||
int i = 0;
|
||||
auto const exp = getDataInt32(runtime, params, i);
|
||||
if (!exp)
|
||||
return hfResult(results, exp.error()); // LCOV_EXCL_LINE
|
||||
|
||||
auto const mant = getDataInt64(runtime, params, i);
|
||||
if (!mant)
|
||||
return hfResult(results, mant.error()); // LCOV_EXCL_LINE
|
||||
|
||||
auto const exp = getDataInt32(runtime, params, i);
|
||||
if (!exp)
|
||||
return hfResult(results, exp.error()); // LCOV_EXCL_LINE
|
||||
|
||||
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->floatSet(*mant, *exp, *rounding), i);
|
||||
return returnResult(runtime, params, results, hf->floatFromMantExp(*mant, *exp, *rounding), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
@@ -2021,28 +1988,6 @@ floatPower_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results
|
||||
return returnResult(runtime, params, results, hf->floatPower(*x, *n, *rounding), i);
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
floatLog_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* runtime = reinterpret_cast<WasmRuntimeWrapper*>(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->floatLog(*x, *rounding), i);
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
namespace test {
|
||||
|
||||
|
||||
@@ -79,10 +79,8 @@ setCommonHostFunctions(HostFunctions* hfs, ImportVec& i)
|
||||
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, floatToMantExp, "float_to_mant_exp", hfs, 130);
|
||||
WASM_IMPORT_FUNC2(i, floatFromMantExp, "float_from_mant_exp", hfs, 100);
|
||||
WASM_IMPORT_FUNC2(i, floatCompare, "float_compare", hfs, 80);
|
||||
WASM_IMPORT_FUNC2(i, floatAdd, "float_add", hfs, 160);
|
||||
WASM_IMPORT_FUNC2(i, floatSubtract, "float_subtract", hfs, 160);
|
||||
@@ -90,7 +88,6 @@ setCommonHostFunctions(HostFunctions* hfs, ImportVec& i)
|
||||
WASM_IMPORT_FUNC2(i, floatDivide, "float_divide", hfs, 300);
|
||||
WASM_IMPORT_FUNC2(i, floatRoot, "float_root", hfs, 5'500);
|
||||
WASM_IMPORT_FUNC2(i, floatPower, "float_pow", hfs, 5'500);
|
||||
WASM_IMPORT_FUNC2(i, floatLog, "float_log", hfs, 12'000);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
|
||||
@@ -368,7 +368,7 @@ ModuleWrapper::buildImports(StorePtr& s, ImportVec const& imports) const
|
||||
if (importTypes.empty())
|
||||
return {};
|
||||
if (imports.empty())
|
||||
throw std::runtime_error("Missing imports");
|
||||
Throw<std::runtime_error>("Empty imports");
|
||||
|
||||
WasmExternVec wimports(importTypes.size());
|
||||
|
||||
@@ -385,7 +385,7 @@ ModuleWrapper::buildImports(StorePtr& s, ImportVec const& imports) const
|
||||
wasm_externkind_t const itype = wasm_externtype_kind(wasm_importtype_type(importType));
|
||||
if ((itype) != WASM_EXTERN_FUNC)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
Throw<std::runtime_error>(
|
||||
"Invalid import type " + std::to_string(itype)); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
@@ -393,46 +393,39 @@ ModuleWrapper::buildImports(StorePtr& s, ImportVec const& imports) const
|
||||
// if ((W_ENV != modName) && (W_HOST_LIB != modName))
|
||||
// continue;
|
||||
|
||||
bool impSet = false;
|
||||
for (auto const& obj : imports)
|
||||
{
|
||||
auto const& imp = obj.second;
|
||||
if (imp.name != fieldName)
|
||||
continue;
|
||||
|
||||
WasmValtypeVec params(makeImpParams(imp));
|
||||
WasmValtypeVec results(makeImpReturn(imp));
|
||||
|
||||
std::unique_ptr<wasm_functype_t, decltype(&wasm_functype_delete)> const ftype(
|
||||
wasm_functype_new(params.get(), results.get()), &wasm_functype_delete);
|
||||
|
||||
params.release();
|
||||
results.release();
|
||||
|
||||
wasm_func_t* func = wasm_func_new_with_env(
|
||||
s.get(),
|
||||
ftype.get(),
|
||||
reinterpret_cast<wasm_func_callback_with_env_t>(imp.wrap),
|
||||
(void*)&obj,
|
||||
nullptr);
|
||||
if (func == nullptr)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
throw std::runtime_error("can't create import function " + imp.name);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
wimports[i] = wasm_func_as_extern(func);
|
||||
++impCnt;
|
||||
impSet = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!impSet)
|
||||
auto const it = imports.find(fieldName);
|
||||
if (it == imports.end())
|
||||
{
|
||||
print_wasm_error("Import not found: " + std::string(fieldName), nullptr, j_);
|
||||
continue; // print all missed import
|
||||
}
|
||||
|
||||
auto const& obj = it->second;
|
||||
auto const& imp = obj.second;
|
||||
|
||||
WasmValtypeVec params(makeImpParams(imp));
|
||||
WasmValtypeVec results(makeImpReturn(imp));
|
||||
|
||||
std::unique_ptr<wasm_functype_t, decltype(&wasm_functype_delete)> const ftype(
|
||||
wasm_functype_new(params.get(), results.get()), &wasm_functype_delete);
|
||||
|
||||
params.release();
|
||||
results.release();
|
||||
|
||||
wasm_func_t* func = wasm_func_new_with_env(
|
||||
s.get(),
|
||||
ftype.get(),
|
||||
reinterpret_cast<wasm_func_callback_with_env_t>(imp.wrap),
|
||||
(void*)&obj,
|
||||
nullptr);
|
||||
if (func == nullptr)
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"can't create import function " + std::string(imp.name)); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
wimports[i] = wasm_func_as_extern(func);
|
||||
++impCnt;
|
||||
}
|
||||
|
||||
if (impCnt != importTypes.size())
|
||||
@@ -442,7 +435,7 @@ ModuleWrapper::buildImports(StorePtr& s, ImportVec const& imports) const
|
||||
std::to_string(importTypes.size()),
|
||||
nullptr,
|
||||
j_);
|
||||
throw std::runtime_error("Missing imports");
|
||||
Throw<std::runtime_error>("Missing imports");
|
||||
}
|
||||
|
||||
return wimports;
|
||||
@@ -741,7 +734,7 @@ checkImports(ImportVec const& imports, HostFunctions* hfs)
|
||||
{
|
||||
for (auto const& obj : imports)
|
||||
{
|
||||
if (hfs != obj.first)
|
||||
if (hfs != obj.second.first)
|
||||
Throw<std::runtime_error>("Imports hf unsync");
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -477,27 +477,15 @@ public:
|
||||
}
|
||||
|
||||
virtual Expected<FloatPair, HostFunctionError>
|
||||
floatToMantissaAndExponent(Slice const& x) const override
|
||||
floatToMantExp(Slice const& x) const override
|
||||
{
|
||||
return wasm_float::floatToMantissaAndExponentImpl(x);
|
||||
return wasm_float::floatToMantExpImpl(x);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatNegate(Slice const& x) const override
|
||||
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) 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
|
||||
{
|
||||
return wasm_float::floatSetImpl(mantissa, exponent, mode);
|
||||
return wasm_float::floatFromMantExpImpl(mantissa, exponent, mode);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
@@ -541,12 +529,6 @@ public:
|
||||
{
|
||||
return wasm_float::floatPowerImpl(x, n, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatLog(Slice const& x, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatLogImpl(x, mode);
|
||||
}
|
||||
};
|
||||
|
||||
struct TestHostFunctionsSink : public TestHostFunctions
|
||||
|
||||
@@ -154,7 +154,7 @@ struct Wasm_test : public beast::unit_test::suite
|
||||
void
|
||||
testWasmLib()
|
||||
{
|
||||
testcase("wasmtime lib test");
|
||||
testcase("wasm lib test");
|
||||
// clang-format off
|
||||
/* The WASM module buffer. */
|
||||
Bytes const wasm = {/* WASM header */
|
||||
@@ -369,7 +369,7 @@ struct Wasm_test : public beast::unit_test::suite
|
||||
TestHostFunctions hfs(env, 0);
|
||||
auto imp = createWasmImport(hfs);
|
||||
for (auto& i : imp)
|
||||
i.second.gas = 0;
|
||||
i.second.second.gas = 0;
|
||||
|
||||
auto re = engine.run(
|
||||
allHostFuncWasm, hfs, 1'000'000, ESCROW_FUNCTION_NAME, {}, imp, env.journal);
|
||||
@@ -498,6 +498,8 @@ struct Wasm_test : public beast::unit_test::suite
|
||||
checkResult(re, -201, 28'965);
|
||||
}
|
||||
|
||||
// This test use log output, so DEBUG_OUTPUT must be disabled.
|
||||
#ifndef DEBUG_OUTPUT
|
||||
{ // fail because recursion too deep
|
||||
|
||||
auto const deepWasm = hexToBytes(deepRecursionHex);
|
||||
@@ -525,6 +527,7 @@ struct Wasm_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(countSubstr(s, "WASMI Error: failure to call func") == 1);
|
||||
BEAST_EXPECT(countSubstr(s, "exception: <finish> failure") > 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
{ // infinite loop
|
||||
auto const infiniteLoopWasm = hexToBytes(infiniteLoopWasmHex);
|
||||
@@ -560,7 +563,7 @@ struct Wasm_test : public beast::unit_test::suite
|
||||
TestLedgerDataProvider hfs(env);
|
||||
ImportVec imports;
|
||||
WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn", &hfs);
|
||||
imports[0].first = nullptr;
|
||||
imports["get_ledger_sqn"].first = nullptr;
|
||||
|
||||
auto& engine = WasmEngine::instance();
|
||||
|
||||
@@ -599,7 +602,7 @@ struct Wasm_test : public beast::unit_test::suite
|
||||
|
||||
TestHostFunctions hfs(env, 0);
|
||||
auto re = runEscrowWasm(floatTestWasm, hfs, 200'000, funcName, {});
|
||||
checkResult(re, 1, 167'965);
|
||||
checkResult(re, 1, 134'938);
|
||||
env.close();
|
||||
}
|
||||
|
||||
@@ -625,7 +628,7 @@ struct Wasm_test : public beast::unit_test::suite
|
||||
auto const codecovWasm = hexToBytes(codecovTestsWasmHex);
|
||||
TestHostFunctions hfs(env, 0);
|
||||
|
||||
auto const allowance = 202'724;
|
||||
auto const allowance = 208'169;
|
||||
auto re = runEscrowWasm(codecovWasm, hfs, allowance, ESCROW_FUNCTION_NAME, {});
|
||||
|
||||
checkResult(re, 1, allowance);
|
||||
|
||||
@@ -1042,21 +1042,6 @@ pub extern "C" fn finish() -> i32 {
|
||||
"float_pow_oob_slice",
|
||||
)
|
||||
});
|
||||
with_buffer::<2, _, _>(|ptr, len| {
|
||||
check_result(
|
||||
unsafe {
|
||||
host::float_log(
|
||||
float.as_ptr().wrapping_add(1_000_000_000),
|
||||
float.len(),
|
||||
ptr,
|
||||
len,
|
||||
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||
)
|
||||
},
|
||||
error_codes::POINTER_OUT_OF_BOUNDS,
|
||||
"float_log_oob_slice",
|
||||
)
|
||||
});
|
||||
|
||||
// invalid UInt32
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@ use xrpl_std::host::trace::DataRepr::AsHex;
|
||||
use xrpl_std::host::trace::{trace, trace_data, trace_num, DataRepr};
|
||||
use xrpl_std::host::{
|
||||
cache_ledger_obj, float_add, float_compare, float_divide, float_from_int, float_from_uint,
|
||||
float_log, float_multiply, float_pow, float_root, float_set, float_subtract,
|
||||
float_multiply, float_pow, float_root, float_subtract,
|
||||
get_ledger_obj_array_len, get_ledger_obj_field, get_ledger_obj_nested_field,
|
||||
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||
};
|
||||
@@ -50,8 +50,8 @@ unsafe extern "C" {
|
||||
rounding: i32,
|
||||
) -> i32;
|
||||
|
||||
#[link_name = "float_to_mantissa_and_exponent"]
|
||||
fn float_to_mantissa_and_exponent(
|
||||
#[link_name = "float_to_mant_exp"]
|
||||
fn float_to_mant_exp(
|
||||
float_ptr: *const u8,
|
||||
float_len: i32,
|
||||
mantissa_ptr: *mut u8,
|
||||
@@ -60,16 +60,14 @@ unsafe extern "C" {
|
||||
exponent_len: i32,
|
||||
) -> i32;
|
||||
|
||||
#[link_name = "float_negate"]
|
||||
fn float_negate(
|
||||
float_ptr: *const u8,
|
||||
float_len: i32,
|
||||
#[link_name = "float_from_mant_exp"]
|
||||
fn float_from_mant_exp(
|
||||
mantissa: i64,
|
||||
exponent: i32,
|
||||
out_ptr: *mut u8,
|
||||
out_len: i32,
|
||||
rounding: i32,
|
||||
) -> i32;
|
||||
|
||||
#[link_name = "float_abs"]
|
||||
fn float_abs(float_ptr: *const u8, float_len: i32, out_ptr: *mut u8, out_len: i32) -> i32;
|
||||
}
|
||||
|
||||
// Float size constant (8 bytes mantissa + 4 bytes exponent)
|
||||
@@ -116,10 +114,10 @@ fn test_float_from_wasm() -> bool {
|
||||
all_pass = false;
|
||||
}
|
||||
|
||||
if FLOAT_SIZE as i32 == unsafe { float_set(2, 123, f.as_mut_ptr(), FLOAT_SIZE, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
|
||||
if FLOAT_SIZE as i32 == unsafe { float_from_mant_exp(123, 2, f.as_mut_ptr(), FLOAT_SIZE as i32, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
|
||||
let _ = trace_float(" float from exp 2, mantissa 123:", &f);
|
||||
} else {
|
||||
let _ = trace(" float from exp 2, mantissa 3: failed");
|
||||
let _ = trace(" float from exp 2, mantissa 123: failed");
|
||||
all_pass = false;
|
||||
}
|
||||
|
||||
@@ -272,7 +270,7 @@ fn test_float_multiply_divide() -> bool {
|
||||
};
|
||||
}
|
||||
let mut f01: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
unsafe { float_set(-1, 1, f01.as_mut_ptr(), FLOAT_SIZE, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||
unsafe { float_from_mant_exp(1, -1, f01.as_mut_ptr(), FLOAT_SIZE as i32, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||
|
||||
if 0 == unsafe { float_compare(f_compute.as_ptr(), FLOAT_SIZE, f01.as_ptr(), FLOAT_SIZE) } {
|
||||
let _ = trace(" repeated divide: good");
|
||||
@@ -436,80 +434,6 @@ fn test_float_root() -> bool {
|
||||
all_pass
|
||||
}
|
||||
|
||||
fn test_float_log() -> bool {
|
||||
let _ = trace("\n$$$ test_float_log $$$");
|
||||
let mut all_pass = true;
|
||||
|
||||
let mut f1000000: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
unsafe {
|
||||
float_from_int(
|
||||
1000000,
|
||||
f1000000.as_mut_ptr(),
|
||||
FLOAT_SIZE,
|
||||
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||
)
|
||||
};
|
||||
let mut f_compute: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
unsafe {
|
||||
float_log(
|
||||
f1000000.as_ptr(),
|
||||
FLOAT_SIZE,
|
||||
f_compute.as_mut_ptr(),
|
||||
FLOAT_SIZE,
|
||||
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||
)
|
||||
};
|
||||
let _ = trace_float(" log_10 of 1000000:", &f_compute);
|
||||
|
||||
all_pass
|
||||
}
|
||||
|
||||
fn test_float_negate() -> bool {
|
||||
let _ = trace("\n$$$ test_float_negate $$$");
|
||||
let mut all_pass = true;
|
||||
|
||||
let mut f_compute: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
unsafe {
|
||||
float_multiply(
|
||||
FLOAT_ONE.as_ptr(),
|
||||
FLOAT_SIZE,
|
||||
FLOAT_NEGATIVE_ONE.as_ptr(),
|
||||
FLOAT_SIZE,
|
||||
f_compute.as_mut_ptr(),
|
||||
FLOAT_SIZE,
|
||||
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||
)
|
||||
};
|
||||
// let _ = trace_float(" float:", &f_compute);
|
||||
if 0 == unsafe { float_compare(FLOAT_NEGATIVE_ONE.as_ptr(), FLOAT_SIZE, f_compute.as_ptr(), FLOAT_SIZE) } {
|
||||
let _ = trace(" negate const 1: good");
|
||||
} else {
|
||||
let _ = trace(" negate const 1: failed");
|
||||
all_pass = false;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
float_multiply(
|
||||
FLOAT_NEGATIVE_ONE.as_ptr(),
|
||||
FLOAT_SIZE,
|
||||
FLOAT_NEGATIVE_ONE.as_ptr(),
|
||||
FLOAT_SIZE,
|
||||
f_compute.as_mut_ptr(),
|
||||
FLOAT_SIZE,
|
||||
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||
)
|
||||
};
|
||||
// let _ = trace_float(" float:", &f_compute);
|
||||
if 0 == unsafe { float_compare(FLOAT_ONE.as_ptr(), FLOAT_SIZE, f_compute.as_ptr(), FLOAT_SIZE) } {
|
||||
let _ = trace(" negate const -1: good");
|
||||
} else {
|
||||
let _ = trace(" negate const -1: failed");
|
||||
all_pass = false;
|
||||
}
|
||||
|
||||
all_pass
|
||||
}
|
||||
|
||||
fn test_float_invert() -> bool {
|
||||
let _ = trace("\n$$$ test_float_invert $$$");
|
||||
let mut all_pass = true;
|
||||
@@ -666,7 +590,7 @@ fn test_float_to_int() -> bool {
|
||||
|
||||
// Test rounding with fractional value (0.1)
|
||||
let mut f01: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
unsafe { float_set(-1, 1, f01.as_mut_ptr(), FLOAT_SIZE, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||
unsafe { float_from_mant_exp(1, -1, f01.as_mut_ptr(), FLOAT_SIZE as i32, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||
let ret = unsafe {
|
||||
float_to_int(
|
||||
f01.as_ptr(),
|
||||
@@ -719,15 +643,15 @@ fn test_float_to_int() -> bool {
|
||||
all_pass
|
||||
}
|
||||
|
||||
fn test_float_to_mantissa_and_exponent() -> bool {
|
||||
let _ = trace("\n$$$ test_float_to_mantissa_and_exponent $$$");
|
||||
fn test_float_to_mant_exp() -> bool {
|
||||
let _ = trace("\n$$$ test_float_to_mant_exp $$$");
|
||||
let mut all_pass = true;
|
||||
|
||||
// Test with FLOAT_ONE (value 1)
|
||||
let mut mantissa_bytes: [u8; 8] = [0u8; 8];
|
||||
let mut exponent_bytes: [u8; 4] = [0u8; 4];
|
||||
let result = unsafe {
|
||||
float_to_mantissa_and_exponent(
|
||||
float_to_mant_exp(
|
||||
FLOAT_ONE.as_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
mantissa_bytes.as_mut_ptr(),
|
||||
@@ -741,15 +665,15 @@ fn test_float_to_mantissa_and_exponent() -> bool {
|
||||
let mantissa = i64::from_le_bytes(mantissa_bytes);
|
||||
let exponent = i32::from_le_bytes(exponent_bytes);
|
||||
if mantissa == 1000000000000000000 && exponent == -18 {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(1): good");
|
||||
let _ = trace(" float_to_mant_exp(1): good");
|
||||
} else {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(1): failed");
|
||||
let _ = trace(" float_to_mant_exp(1): failed");
|
||||
let _ = trace_num(" expected mantissa 1000000000000000000, got:", mantissa);
|
||||
let _ = trace_num(" expected exponent -18, got:", exponent as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
} else {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(1): failed with error");
|
||||
let _ = trace(" float_to_mant_exp(1): failed with error");
|
||||
let _ = trace_num(" error code:", result as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
@@ -758,7 +682,7 @@ fn test_float_to_mantissa_and_exponent() -> bool {
|
||||
let mut mantissa_bytes: [u8; 8] = [0u8; 8];
|
||||
let mut exponent_bytes: [u8; 4] = [0u8; 4];
|
||||
let result = unsafe {
|
||||
float_to_mantissa_and_exponent(
|
||||
float_to_mant_exp(
|
||||
FLOAT_NEGATIVE_ONE.as_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
mantissa_bytes.as_mut_ptr(),
|
||||
@@ -772,15 +696,15 @@ fn test_float_to_mantissa_and_exponent() -> bool {
|
||||
let mantissa = i64::from_le_bytes(mantissa_bytes);
|
||||
let exponent = i32::from_le_bytes(exponent_bytes);
|
||||
if mantissa == -1000000000000000000 && exponent == -18 {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(-1): good");
|
||||
let _ = trace(" float_to_mant_exp(-1): good");
|
||||
} else {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(-1): failed");
|
||||
let _ = trace(" float_to_mant_exp(-1): failed");
|
||||
let _ = trace_num(" expected mantissa -1000000000000000000, got:", mantissa);
|
||||
let _ = trace_num(" expected exponent -18, got:", exponent as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
} else {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(-1): failed with error");
|
||||
let _ = trace(" float_to_mant_exp(-1): failed with error");
|
||||
let _ = trace_num(" error code:", result as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
@@ -792,7 +716,7 @@ fn test_float_to_mantissa_and_exponent() -> bool {
|
||||
let mut mantissa_bytes: [u8; 8] = [0u8; 8];
|
||||
let mut exponent_bytes: [u8; 4] = [0u8; 4];
|
||||
let result = unsafe {
|
||||
float_to_mantissa_and_exponent(
|
||||
float_to_mant_exp(
|
||||
f10.as_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
mantissa_bytes.as_mut_ptr(),
|
||||
@@ -806,15 +730,15 @@ fn test_float_to_mantissa_and_exponent() -> bool {
|
||||
let mantissa = i64::from_le_bytes(mantissa_bytes);
|
||||
let exponent = i32::from_le_bytes(exponent_bytes);
|
||||
if mantissa == 1000000000000000000 && exponent == -17 {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(10): good");
|
||||
let _ = trace(" float_to_mant_exp(10): good");
|
||||
} else {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(10): failed");
|
||||
let _ = trace(" float_to_mant_exp(10): failed");
|
||||
let _ = trace_num(" expected mantissa 1000000000000000000, got:", mantissa);
|
||||
let _ = trace_num(" expected exponent -17, got:", exponent as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
} else {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(10): failed with error");
|
||||
let _ = trace(" float_to_mant_exp(10): failed with error");
|
||||
let _ = trace_num(" error code:", result as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
@@ -826,7 +750,7 @@ fn test_float_to_mantissa_and_exponent() -> bool {
|
||||
let mut mantissa_bytes: [u8; 8] = [0u8; 8];
|
||||
let mut exponent_bytes: [u8; 4] = [0u8; 4];
|
||||
let result = unsafe {
|
||||
float_to_mantissa_and_exponent(
|
||||
float_to_mant_exp(
|
||||
f0.as_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
mantissa_bytes.as_mut_ptr(),
|
||||
@@ -840,15 +764,15 @@ fn test_float_to_mantissa_and_exponent() -> bool {
|
||||
let mantissa = i64::from_le_bytes(mantissa_bytes);
|
||||
let exponent = i32::from_le_bytes(exponent_bytes);
|
||||
if mantissa == 0 && exponent == -2147483648 {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(0): good");
|
||||
let _ = trace(" float_to_mant_exp(0): good");
|
||||
} else {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(0): failed");
|
||||
let _ = trace(" float_to_mant_exp(0): failed");
|
||||
let _ = trace_num(" expected mantissa 0, got:", mantissa);
|
||||
let _ = trace_num(" expected exponent -2147483648, got:", exponent as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
} else {
|
||||
let _ = trace(" float_to_mantissa_and_exponent(0): failed with error");
|
||||
let _ = trace(" float_to_mant_exp(0): failed with error");
|
||||
let _ = trace_num(" error code:", result as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
@@ -856,189 +780,6 @@ fn test_float_to_mantissa_and_exponent() -> bool {
|
||||
all_pass
|
||||
}
|
||||
|
||||
fn test_float_negate_host() -> bool {
|
||||
let _ = trace("\n$$$ test_float_negate $$$");
|
||||
let mut all_pass = true;
|
||||
|
||||
// Test with FLOAT_ONE (value 1) -> should become -1
|
||||
let mut result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
let ret = unsafe {
|
||||
float_negate(
|
||||
FLOAT_ONE.as_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
result.as_mut_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
)
|
||||
};
|
||||
|
||||
if ret == FLOAT_SIZE as i32 {
|
||||
if result == FLOAT_NEGATIVE_ONE {
|
||||
let _ = trace(" float_negate(1): good");
|
||||
} else {
|
||||
let _ = trace(" float_negate(1): failed - result mismatch");
|
||||
all_pass = false;
|
||||
}
|
||||
} else {
|
||||
let _ = trace(" float_negate(1): failed with error");
|
||||
let _ = trace_num(" error code:", ret as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
|
||||
// Test with FLOAT_NEGATIVE_ONE (value -1) -> should become 1
|
||||
let mut result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
let ret = unsafe {
|
||||
float_negate(
|
||||
FLOAT_NEGATIVE_ONE.as_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
result.as_mut_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
)
|
||||
};
|
||||
|
||||
if ret == FLOAT_SIZE as i32 {
|
||||
if result == FLOAT_ONE {
|
||||
let _ = trace(" float_negate(-1): good");
|
||||
} else {
|
||||
let _ = trace(" float_negate(-1): failed - result mismatch");
|
||||
all_pass = false;
|
||||
}
|
||||
} else {
|
||||
let _ = trace(" float_negate(-1): failed with error");
|
||||
let _ = trace_num(" error code:", ret as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
|
||||
// Test with zero -> should remain zero
|
||||
let mut f0: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
unsafe { float_from_int(0, f0.as_mut_ptr(), FLOAT_SIZE, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||
|
||||
let mut result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
let ret = unsafe {
|
||||
float_negate(f0.as_ptr(), FLOAT_SIZE as i32, result.as_mut_ptr(), FLOAT_SIZE as i32)
|
||||
};
|
||||
|
||||
if ret == FLOAT_SIZE as i32 {
|
||||
if result == f0 {
|
||||
let _ = trace(" float_negate(0): good");
|
||||
} else {
|
||||
let _ = trace(" float_negate(0): failed - result mismatch");
|
||||
all_pass = false;
|
||||
}
|
||||
} else {
|
||||
let _ = trace(" float_negate(0): failed with error");
|
||||
let _ = trace_num(" error code:", ret as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
|
||||
all_pass
|
||||
}
|
||||
|
||||
fn test_float_abs_host() -> bool {
|
||||
let _ = trace("\n$$$ test_float_abs $$$");
|
||||
let mut all_pass = true;
|
||||
|
||||
// Test with FLOAT_ONE (value 1) -> should remain 1
|
||||
let mut result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
let ret = unsafe {
|
||||
float_abs(
|
||||
FLOAT_ONE.as_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
result.as_mut_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
)
|
||||
};
|
||||
|
||||
if ret == FLOAT_SIZE as i32 {
|
||||
if result == FLOAT_ONE {
|
||||
let _ = trace(" float_abs(1): good");
|
||||
} else {
|
||||
let _ = trace(" float_abs(1): failed - result mismatch");
|
||||
all_pass = false;
|
||||
}
|
||||
} else {
|
||||
let _ = trace(" float_abs(1): failed with error");
|
||||
let _ = trace_num(" error code:", ret as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
|
||||
// Test with FLOAT_NEGATIVE_ONE (value -1) -> should become 1
|
||||
let mut result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
let ret = unsafe {
|
||||
float_abs(
|
||||
FLOAT_NEGATIVE_ONE.as_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
result.as_mut_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
)
|
||||
};
|
||||
|
||||
if ret == FLOAT_SIZE as i32 {
|
||||
if result == FLOAT_ONE {
|
||||
let _ = trace(" float_abs(-1): good");
|
||||
} else {
|
||||
let _ = trace(" float_abs(-1): failed - result mismatch");
|
||||
all_pass = false;
|
||||
}
|
||||
} else {
|
||||
let _ = trace(" float_abs(-1): failed with error");
|
||||
let _ = trace_num(" error code:", ret as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
|
||||
// Test with zero -> should remain zero
|
||||
let mut f0: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
unsafe { float_from_int(0, f0.as_mut_ptr(), FLOAT_SIZE, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||
|
||||
let mut result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
let ret =
|
||||
unsafe { float_abs(f0.as_ptr(), FLOAT_SIZE as i32, result.as_mut_ptr(), FLOAT_SIZE as i32) };
|
||||
|
||||
if ret == FLOAT_SIZE as i32 {
|
||||
if result == f0 {
|
||||
let _ = trace(" float_abs(0): good");
|
||||
} else {
|
||||
let _ = trace(" float_abs(0): failed - result mismatch");
|
||||
all_pass = false;
|
||||
}
|
||||
} else {
|
||||
let _ = trace(" float_abs(0): failed with error");
|
||||
let _ = trace_num(" error code:", ret as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
|
||||
// Test with negative value -> should become positive
|
||||
let mut f_neg10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
unsafe { float_from_int(-10, f_neg10.as_mut_ptr(), FLOAT_SIZE, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||
|
||||
let mut f_pos10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
unsafe { float_from_int(10, f_pos10.as_mut_ptr(), FLOAT_SIZE, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||
|
||||
let mut result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE];
|
||||
let ret = unsafe {
|
||||
float_abs(
|
||||
f_neg10.as_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
result.as_mut_ptr(),
|
||||
FLOAT_SIZE as i32,
|
||||
)
|
||||
};
|
||||
|
||||
if ret == FLOAT_SIZE as i32 {
|
||||
if result == f_pos10 {
|
||||
let _ = trace(" float_abs(-10): good");
|
||||
} else {
|
||||
let _ = trace(" float_abs(-10): failed - result mismatch");
|
||||
all_pass = false;
|
||||
}
|
||||
} else {
|
||||
let _ = trace(" float_abs(-10): failed with error");
|
||||
let _ = trace_num(" error code:", ret as i64);
|
||||
all_pass = false;
|
||||
}
|
||||
|
||||
all_pass
|
||||
}
|
||||
|
||||
fn test_float_from_stamount() -> bool {
|
||||
let _ = trace("\n$$$ test_float_from_stamount $$$");
|
||||
let mut all_pass = true;
|
||||
@@ -1203,13 +944,9 @@ pub extern "C" fn finish() -> i32 {
|
||||
all_pass &= test_float_multiply_divide();
|
||||
all_pass &= test_float_pow();
|
||||
all_pass &= test_float_root();
|
||||
all_pass &= test_float_log();
|
||||
all_pass &= test_float_negate();
|
||||
all_pass &= test_float_invert();
|
||||
all_pass &= test_float_to_int();
|
||||
all_pass &= test_float_to_mantissa_and_exponent();
|
||||
all_pass &= test_float_negate_host();
|
||||
all_pass &= test_float_abs_host();
|
||||
all_pass &= test_float_to_mant_exp();
|
||||
all_pass &= test_float_from_stamount();
|
||||
all_pass &= test_float_from_stnumber();
|
||||
|
||||
|
||||
@@ -1542,78 +1542,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_log10()
|
||||
{
|
||||
auto const scale = Number::getMantissaScale();
|
||||
testcase << "test_lg " << to_string(scale);
|
||||
|
||||
using Case = std::tuple<Number, Number>;
|
||||
auto test = [this](auto const& c) {
|
||||
for (auto const& [x, z] : c)
|
||||
{
|
||||
auto const result = log10(x);
|
||||
std::stringstream ss;
|
||||
ss << "lg(" << x << ") = " << result << ". Expected: " << z;
|
||||
// std::cout << ss.str() << std::endl;
|
||||
BEAST_EXPECTS(result == z, ss.str());
|
||||
}
|
||||
};
|
||||
|
||||
auto const cSmall = std::to_array<Case>(
|
||||
{{Number{2}, Number{3'010'299'956'639'811ll, -16}},
|
||||
{Number{2'000'000}, Number{6'301'029'995'663'985ll, -15}},
|
||||
{Number{2, -30}, Number{-2'969'897'000'433'602ll, -14}},
|
||||
{Number{1}, Number{0}},
|
||||
{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{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)
|
||||
{
|
||||
test(cSmall);
|
||||
}
|
||||
else
|
||||
{
|
||||
NumberRoundModeGuard const mg(Number::towards_zero);
|
||||
test(cLarge);
|
||||
}
|
||||
|
||||
{
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
log10(Number{-2});
|
||||
}
|
||||
catch (std::runtime_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
BEAST_EXPECT(caught);
|
||||
caught = false;
|
||||
|
||||
try
|
||||
{
|
||||
log10(Number());
|
||||
}
|
||||
catch (std::runtime_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
BEAST_EXPECT(caught);
|
||||
caught = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@@ -1641,7 +1569,6 @@ public:
|
||||
test_truncate();
|
||||
testRounding();
|
||||
testInt64();
|
||||
test_log10();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user