mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-03 17:35:51 +00:00
Float point Hostfunctions unit tests (#5656)
* Added direct unittests for float hostfunctions
This commit is contained in:
@@ -58,6 +58,13 @@ private:
|
||||
normalize();
|
||||
|
||||
public:
|
||||
/* The range for the mantissa when normalized */
|
||||
static std::int64_t constexpr minMantissa = 1000000000000000ull;
|
||||
static std::int64_t constexpr maxMantissa = 9999999999999999ull;
|
||||
/* The range for the exponent when normalized */
|
||||
static int constexpr minExponent = -96;
|
||||
static int constexpr maxExponent = 80;
|
||||
|
||||
IOUAmount() = default;
|
||||
explicit IOUAmount(Number const& other);
|
||||
IOUAmount(beast::Zero);
|
||||
|
||||
@@ -58,13 +58,6 @@ setSTNumberSwitchover(bool v)
|
||||
*getStaticSTNumberSwitchover() = v;
|
||||
}
|
||||
|
||||
/* The range for the mantissa when normalized */
|
||||
static std::int64_t constexpr minMantissa = 1000000000000000ull;
|
||||
static std::int64_t constexpr maxMantissa = 9999999999999999ull;
|
||||
/* The range for the exponent when normalized */
|
||||
static int constexpr minExponent = -96;
|
||||
static int constexpr maxExponent = 80;
|
||||
|
||||
IOUAmount
|
||||
IOUAmount::minPositiveAmount()
|
||||
{
|
||||
@@ -312,7 +305,8 @@ mulRatio(
|
||||
{
|
||||
if (!result)
|
||||
{
|
||||
return IOUAmount(-minMantissa, minExponent);
|
||||
return IOUAmount(
|
||||
-IOUAmount::minMantissa, IOUAmount::minExponent);
|
||||
}
|
||||
// This subtraction cannot underflow because `result` is not zero
|
||||
return IOUAmount(result.mantissa() - 1, result.exponent());
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -825,9 +825,11 @@ WasmHostFunctionsImpl::floatLog(Slice const& x, int32_t mode)
|
||||
|
||||
class Number2 : public Number
|
||||
{
|
||||
bool good_;
|
||||
|
||||
public:
|
||||
enum Issue { XRP, MPT, IOU };
|
||||
|
||||
protected:
|
||||
bool good_;
|
||||
Issue issue_;
|
||||
|
||||
public:
|
||||
@@ -847,8 +849,9 @@ public:
|
||||
int32_t const e =
|
||||
static_cast<uint8_t>((v >> (64 - 10)) & ((1ull << 8) - 1));
|
||||
int64_t const m = neg * (v & ((1ull << 54) - 1));
|
||||
x = !m ? Number() : Number(m, e - 97);
|
||||
if (m && (x.exponent() > 80 || x.exponent() < -96))
|
||||
x = !m || (e < 1) ? Number()
|
||||
: Number(m, e + IOUAmount::minExponent - 1);
|
||||
if (m && (x.exponent() > IOUAmount::maxExponent))
|
||||
return; // invalid number
|
||||
issue_ = IOU;
|
||||
}
|
||||
@@ -871,6 +874,10 @@ public:
|
||||
good_ = true;
|
||||
}
|
||||
|
||||
Number2() : Number(), good_(true), issue_(IOU)
|
||||
{
|
||||
}
|
||||
|
||||
Number2(int64_t x) : Number(x), good_(true), issue_(IOU)
|
||||
{
|
||||
}
|
||||
@@ -904,6 +911,18 @@ public:
|
||||
return good_;
|
||||
}
|
||||
|
||||
Issue
|
||||
getIssue() const
|
||||
{
|
||||
return issue_;
|
||||
}
|
||||
|
||||
void
|
||||
setIssue(Issue i)
|
||||
{
|
||||
issue_ = i;
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
toBytes() const
|
||||
{
|
||||
@@ -917,18 +936,24 @@ public:
|
||||
{
|
||||
if (exponent() != std::numeric_limits<int>::lowest())
|
||||
return Unexpected(
|
||||
HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
HostFunctionError::
|
||||
FLOAT_COMPUTATION_ERROR); // LCOV_EXCL_LINE
|
||||
}
|
||||
else if (exponent() > 80 || exponent() < -96)
|
||||
else if (exponent() > IOUAmount::maxExponent)
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
else if (exponent() < IOUAmount::minExponent)
|
||||
return Number2().toBytes();
|
||||
|
||||
uint64_t absM = mantissa() >= 0 ? mantissa() : -mantissa();
|
||||
if (absM > ((1ull << 54) - 1))
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
return Unexpected(
|
||||
HostFunctionError::
|
||||
FLOAT_COMPUTATION_ERROR); // LCOV_EXCL_LINE
|
||||
|
||||
v |= absM;
|
||||
|
||||
int const e = (!mantissa() ? 0 : exponent()) + 97;
|
||||
int const e =
|
||||
(!mantissa() ? 0 : exponent()) - IOUAmount::minExponent + 1;
|
||||
v |= ((uint64_t)e) << 54;
|
||||
}
|
||||
else if (issue_ == MPT)
|
||||
@@ -950,6 +975,16 @@ public:
|
||||
Serializer msg;
|
||||
msg.add64(v);
|
||||
auto const data = msg.getData();
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
std::cout << "m: " << std::setw(20) << mantissa()
|
||||
<< ", e: " << std::setw(12) << 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;
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -958,7 +993,7 @@ protected:
|
||||
toUInt(unsigned bits) const
|
||||
{
|
||||
if (bits >= sizeof(uint64_t) * 8)
|
||||
return std::numeric_limits<uint64_t>::max();
|
||||
return std::numeric_limits<uint64_t>::max(); // LCOV_EXCL_LINE
|
||||
|
||||
uint64_t maxV = (1ull << bits) - 1;
|
||||
uint64_t absM = mantissa() >= 0 ? mantissa() : -mantissa();
|
||||
@@ -969,8 +1004,9 @@ protected:
|
||||
{
|
||||
for (int i = 0; i > exponent(); --i)
|
||||
{
|
||||
// underflow
|
||||
if (absM < 10)
|
||||
return std::numeric_limits<uint64_t>::max(); // underflow
|
||||
return std::numeric_limits<uint64_t>::max();
|
||||
absM /= 10;
|
||||
}
|
||||
}
|
||||
@@ -978,8 +1014,9 @@ protected:
|
||||
{
|
||||
for (int i = 0; i < exponent(); ++i)
|
||||
{
|
||||
// overflow
|
||||
if (absM > maxV / 10)
|
||||
return std::numeric_limits<uint64_t>::max(); // overflow
|
||||
return std::numeric_limits<uint64_t>::max();
|
||||
absM *= 10;
|
||||
}
|
||||
}
|
||||
@@ -1041,15 +1078,14 @@ floatFromIntImpl(int64_t x, int32_t mode)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
Number2 num(x);
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
return num.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
@@ -1062,15 +1098,14 @@ floatFromUintImpl(uint64_t x, int32_t mode)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
Number2 num(x);
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
return num.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
@@ -1082,8 +1117,6 @@ floatSetImpl(int64_t mantissa, int32_t exponent, int32_t mode)
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 num(mantissa, exponent);
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
return num.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
@@ -1105,10 +1138,12 @@ floatCompareImpl(Slice const& x, Slice const& y)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
return xx < yy ? 2 : (xx == yy ? 0 : 1);
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
@@ -1127,12 +1162,15 @@ floatAddImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 res = xx + yy;
|
||||
res.setIssue(xx.getIssue());
|
||||
return res.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
@@ -1150,12 +1188,15 @@ floatSubtractImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 res = xx - yy;
|
||||
res.setIssue(xx.getIssue());
|
||||
return res.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
@@ -1173,12 +1214,15 @@ floatMultiplyImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 res = xx * yy;
|
||||
res.setIssue(xx.getIssue());
|
||||
return res.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
@@ -1196,6 +1240,7 @@ floatDivideImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 res = xx / yy;
|
||||
res.setIssue(xx.getIssue());
|
||||
return res.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
@@ -1209,6 +1254,9 @@ floatRootImpl(Slice const& x, int32_t n, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (n < 1)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
@@ -1216,14 +1264,17 @@ floatRootImpl(Slice const& x, int32_t n, int32_t mode)
|
||||
Number2 xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 const res(root(xx, n));
|
||||
|
||||
Number2 res(root(xx, n));
|
||||
res.setIssue(xx.getIssue());
|
||||
return res.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
@@ -1231,6 +1282,9 @@ floatPowerImpl(Slice const& x, int32_t n, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (n < 0)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
|
||||
SetRound rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
@@ -1241,8 +1295,8 @@ floatPowerImpl(Slice const& x, int32_t n, int32_t mode)
|
||||
if (xx == Number() && !n)
|
||||
return Unexpected(HostFunctionError::INVALID_PARAMS);
|
||||
|
||||
Number2 const res(power(xx, n, 1));
|
||||
|
||||
Number2 res(power(xx, n, 1));
|
||||
res.setIssue(xx.getIssue());
|
||||
return res.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
@@ -1263,14 +1317,17 @@ floatLogImpl(Slice const& x, int32_t mode)
|
||||
Number2 xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FLOAT_INPUT_MALFORMED);
|
||||
Number2 const res(lg(xx));
|
||||
|
||||
Number2 res(lg(xx));
|
||||
res.setIssue(xx.getIssue());
|
||||
return res.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return Unexpected(HostFunctionError::FLOAT_COMPUTATION_ERROR);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
Reference in New Issue
Block a user