Skip to content

Commit

Permalink
[FOLD] Merge with the latest Number
Browse files Browse the repository at this point in the history
  • Loading branch information
HowardHinnant authored and gregtatcam committed Nov 10, 2022
1 parent dd7f8db commit 2fa59f1
Show file tree
Hide file tree
Showing 11 changed files with 1,291 additions and 841 deletions.
4 changes: 0 additions & 4 deletions src/ripple/basics/IOUAmount.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,6 @@ mulRatio(
std::uint32_t den,
bool roundUp);

// Since IOUAmount and STAmount do not have access to a ledger, this
// is needed to put low-level routines on an amendment switch. Only
// transactions need to use this switchover. Outside of a transaction
// it's safe to unconditionally use the new behavior.
extern LocalValue<bool> stNumberSwitchover;

/** RAII class to set and restore the Number switchover.
Expand Down
19 changes: 19 additions & 0 deletions src/ripple/basics/Number.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <ripple/basics/XRPAmount.h>
#include <cstdint>
#include <limits>
#include <ostream>
#include <string>

Expand Down Expand Up @@ -336,6 +337,24 @@ squelch(Number const& x, Number const& limit) noexcept
return x;
}

class saveNumberRoundMode
{
Number::rounding_mode mode_;

public:
~saveNumberRoundMode()
{
Number::setround(mode_);
}
explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept
: mode_{mode}
{
}
saveNumberRoundMode(saveNumberRoundMode const&) = delete;
saveNumberRoundMode&
operator=(saveNumberRoundMode const&) = delete;
};

} // namespace ripple

#endif // RIPPLE_BASICS_NUMBER_H_INCLUDED
75 changes: 37 additions & 38 deletions src/ripple/basics/impl/IOUAmount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ IOUAmount::minPositiveAmount()
void
IOUAmount::normalize()
{
if (mantissa_ == 0)
{
*this = beast::zero;
return;
}

if (*stNumberSwitchover)
{
Number v{mantissa_, exponent_};
Expand All @@ -56,11 +62,6 @@ IOUAmount::normalize()
*this = beast::zero;
return;
}
if (mantissa_ == 0)
{
*this = beast::zero;
return;
}

bool const negative = (mantissa_ < 0);

Expand Down Expand Up @@ -107,48 +108,46 @@ IOUAmount::IOUAmount(Number const& other)
IOUAmount&
IOUAmount::operator+=(IOUAmount const& other)
{
if (other == beast::zero)
return *this;

if (*this == beast::zero)
{
*this = other;
return *this;
}

if (*stNumberSwitchover)
{
*this = IOUAmount{Number{*this} + Number{other}};
return *this;
}
else
{
if (other == beast::zero)
return *this;

if (*this == beast::zero)
{
*this = other;
return *this;
}
auto m = other.mantissa_;
auto e = other.exponent_;

auto m = other.mantissa_;
auto e = other.exponent_;

while (exponent_ < e)
{
mantissa_ /= 10;
++exponent_;
}

while (e < exponent_)
{
m /= 10;
++e;
}
while (exponent_ < e)
{
mantissa_ /= 10;
++exponent_;
}

// This addition cannot overflow an std::int64_t but we may throw from
// normalize if the result isn't representable.
mantissa_ += m;
while (e < exponent_)
{
m /= 10;
++e;
}

if (mantissa_ >= -10 && mantissa_ <= 10)
{
*this = beast::zero;
return *this;
}
// This addition cannot overflow an std::int64_t but we may throw from
// normalize if the result isn't representable.
mantissa_ += m;

normalize();
if (mantissa_ >= -10 && mantissa_ <= 10)
{
*this = beast::zero;
return *this;
}

normalize();
return *this;
}

Expand Down
59 changes: 32 additions & 27 deletions src/ripple/basics/impl/Number.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include <type_traits>
#include <utility>

#ifdef _MSVC_LANG
#ifdef BOOST_COMP_MSVC
#include <boost/multiprecision/cpp_int.hpp>
using uint128_t = boost::multiprecision::uint128_t;
#else // !defined(_MSVC_LANG)
Expand Down Expand Up @@ -130,32 +130,37 @@ int
Number::Guard::round() noexcept
{
auto mode = Number::getround();
switch (mode)

if (mode == towards_zero)
return -1;

if (mode == downward)
{
case to_nearest:
if (digits_ > 0x5000'0000'0000'0000)
return 1;
if (digits_ < 0x5000'0000'0000'0000)
return -1;
if (xbit_)
return 1;
return 0;
case towards_zero:
return -1;
case downward:
if (sbit_)
{
if (digits_ > 0 || xbit_)
return 1;
}
return -1;
case upward:
if (sbit_)
return -1;
if (sbit_)
{
if (digits_ > 0 || xbit_)
return 1;
}
return -1;
}

if (mode == upward)
{
if (sbit_)
return -1;
if (digits_ > 0 || xbit_)
return 1;
return -1;
}

// assume round to nearest if mode is not one of the predefined values
if (digits_ > 0x5000'0000'0000'0000)
return 1;
if (digits_ < 0x5000'0000'0000'0000)
return -1;
if (xbit_)
return 1;
return 0;
}

// Number
Expand All @@ -171,9 +176,9 @@ Number::normalize()
return;
}
bool const negative = (mantissa_ < 0);
if (negative)
mantissa_ = -mantissa_;
auto m = static_cast<std::make_unsigned_t<rep>>(mantissa_);
if (negative)
m = -m;
while ((m < minMantissa) && (exponent_ > minExponent))
{
m *= 10;
Expand Down Expand Up @@ -506,8 +511,8 @@ to_string(Number const& amount)

assert(exponent + 43 > 0);

size_t const pad_prefix = 27;
size_t const pad_suffix = 23;
ptrdiff_t const pad_prefix = 27;
ptrdiff_t const pad_suffix = 23;

std::string const raw_value(std::to_string(mantissa));
std::string val;
Expand All @@ -517,7 +522,7 @@ to_string(Number const& amount)
val.append(raw_value);
val.append(pad_suffix, '0');

size_t const offset(exponent + 43);
ptrdiff_t const offset(exponent + 43);

auto pre_from(val.begin());
auto const pre_to(val.begin() + offset);
Expand Down
38 changes: 25 additions & 13 deletions src/ripple/protocol/impl/STAmount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -725,24 +725,36 @@ STAmount::canonicalize()
"Native currency amount out of range");
}

while (mOffset < 0)
if (*stNumberSwitchover && *stAmountCanonicalizeSwitchover)
{
mValue /= 10;
++mOffset;
Number num(
mIsNegative ? -mValue : mValue, mOffset, Number::unchecked{});
XRPAmount xrp{num};
mIsNegative = xrp.drops() < 0;
mValue = mIsNegative ? -xrp.drops() : xrp.drops();
mOffset = 0;
}

while (mOffset > 0)
else
{
if (*stAmountCanonicalizeSwitchover)
while (mOffset < 0)
{
mValue /= 10;
++mOffset;
}

while (mOffset > 0)
{
// N.B. do not move the overflow check to after the
// multiplication
if (mValue > cMaxNativeN)
Throw<std::runtime_error>(
"Native currency amount out of range");
if (*stAmountCanonicalizeSwitchover)
{
// N.B. do not move the overflow check to after the
// multiplication
if (mValue > cMaxNativeN)
Throw<std::runtime_error>(
"Native currency amount out of range");
}
mValue *= 10;
--mOffset;
}
mValue *= 10;
--mOffset;
}

if (mValue > cMaxNativeN)
Expand Down
22 changes: 14 additions & 8 deletions src/test/app/NFToken_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2335,7 +2335,13 @@ class NFToken_test : public beast::unit_test::suite

// See the impact of rounding when the nft is sold for small amounts
// of drops.
for (auto NumberSwitchOver : {true})
{
if (NumberSwitchOver)
env.enableFeature(fixUniversalNumber);
else
env.disableFeature(fixUniversalNumber);

// An nft with a transfer fee of 1 basis point.
uint256 const nftID =
token::getNextID(env, alice, 0u, tfTransferable, 1);
Expand All @@ -2360,16 +2366,16 @@ class NFToken_test : public beast::unit_test::suite

// minter sells to carol. The payment is just small enough that
// alice does not get any transfer fee.
auto pmt = NumberSwitchOver ? drops(50000) : drops(99999);
STAmount carolBalance = env.balance(carol);
uint256 const minterSellOfferIndex =
keylet::nftoffer(minter, env.seq(minter)).key;
env(token::createOffer(minter, nftID, drops(99999)),
txflags(tfSellNFToken));
env(token::createOffer(minter, nftID, pmt), txflags(tfSellNFToken));
env.close();
env(token::acceptSellOffer(carol, minterSellOfferIndex));
env.close();
minterBalance += drops(99999) - fee;
carolBalance -= drops(99999) + fee;
minterBalance += pmt - fee;
carolBalance -= pmt + fee;
BEAST_EXPECT(env.balance(alice) == aliceBalance);
BEAST_EXPECT(env.balance(minter) == minterBalance);
BEAST_EXPECT(env.balance(carol) == carolBalance);
Expand All @@ -2379,13 +2385,13 @@ class NFToken_test : public beast::unit_test::suite
STAmount beckyBalance = env.balance(becky);
uint256 const beckyBuyOfferIndex =
keylet::nftoffer(becky, env.seq(becky)).key;
env(token::createOffer(becky, nftID, drops(100000)),
token::owner(carol));
pmt = NumberSwitchOver ? drops(50001) : drops(100000);
env(token::createOffer(becky, nftID, pmt), token::owner(carol));
env.close();
env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
env.close();
carolBalance += drops(99999) - fee;
beckyBalance -= drops(100000) + fee;
carolBalance += pmt - drops(1) - fee;
beckyBalance -= pmt + fee;
aliceBalance += drops(1);

BEAST_EXPECT(env.balance(alice) == aliceBalance);
Expand Down
Loading

0 comments on commit 2fa59f1

Please sign in to comment.