mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-23 07:10:53 +00:00
fix: Handle rounding just above kMaxRep more accurately (#7389)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com> Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
@@ -101,6 +102,39 @@ struct STNumber_test : public beast::unit_test::Suite
|
||||
BEAST_EXPECT(numberFromJson(sfNumber, "-0.000e6") == STNumber(sfNumber, 0));
|
||||
|
||||
{
|
||||
auto const parseNumber = [](std::string const& boundary) {
|
||||
return numberFromJson(sfNumber, boundary);
|
||||
};
|
||||
auto const expectParseThrows = [this, &parseNumber](std::string const& boundary) {
|
||||
try
|
||||
{
|
||||
parseNumber(boundary);
|
||||
fail();
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
BEAST_EXPECT(std::string(e.what()) == "number cannot be represented");
|
||||
}
|
||||
};
|
||||
|
||||
// Small rejects this; large scales parse it as 9223372036854775800e-1.
|
||||
auto constexpr positiveBoundary = "922337203685477580";
|
||||
auto constexpr negativeBoundary = "-922337203685477580";
|
||||
if (Number::getMantissaScale() == MantissaRange::MantissaScale::Small)
|
||||
{
|
||||
expectParseThrows(positiveBoundary);
|
||||
expectParseThrows(negativeBoundary);
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
parseNumber(positiveBoundary) ==
|
||||
STNumber(sfNumber, Number{922'337'203'685'477'580, 0}));
|
||||
BEAST_EXPECT(
|
||||
parseNumber(negativeBoundary) ==
|
||||
STNumber(sfNumber, Number{-922'337'203'685'477'580, 0}));
|
||||
}
|
||||
|
||||
NumberRoundModeGuard const mg(Number::RoundingMode::TowardsZero);
|
||||
// maxint64 9,223,372,036,854,775,807
|
||||
auto const maxInt = std::to_string(std::numeric_limits<std::int64_t>::max());
|
||||
@@ -108,23 +142,19 @@ struct STNumber_test : public beast::unit_test::Suite
|
||||
auto const minInt = std::to_string(std::numeric_limits<std::int64_t>::min());
|
||||
if (Number::getMantissaScale() == MantissaRange::MantissaScale::Small)
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
numberFromJson(sfNumber, maxInt) ==
|
||||
STNumber(sfNumber, Number{9'223'372'036'854'775, 3}));
|
||||
BEAST_EXPECT(
|
||||
numberFromJson(sfNumber, minInt) ==
|
||||
STNumber(sfNumber, Number{-9'223'372'036'854'775, 3}));
|
||||
// min/maxInt can't be exactly represented with the small mantissa, so they
|
||||
// don't parse, and are expected to throw.
|
||||
expectParseThrows(maxInt);
|
||||
expectParseThrows(minInt);
|
||||
}
|
||||
else
|
||||
{
|
||||
// with large mantissas, maxint is fine
|
||||
BEAST_EXPECT(
|
||||
numberFromJson(sfNumber, maxInt) ==
|
||||
parseNumber(maxInt) ==
|
||||
STNumber(sfNumber, Number{9'223'372'036'854'775'807, 0}));
|
||||
BEAST_EXPECT(
|
||||
numberFromJson(sfNumber, minInt) ==
|
||||
STNumber(
|
||||
sfNumber,
|
||||
Number{true, 9'223'372'036'854'775'808ULL, 0, Number::Normalized{}}));
|
||||
// but minint's mantissa is > kMaxRep, and so rounds, and thus can't be parsed
|
||||
expectParseThrows(minInt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user