mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
- Refactor Number internals away from int64 to uint64 & a sign flag
- ctors and accessors use `rep`. Very few things expose
`internalrep`.
- An exception is "unchecked" and the new "normalized", which explicitly
take an internalrep. But with those special control flags, it's easier
to distinguish and control when they are used.
- For now, skip the larger mantissas in AMM transactions and tests
- Remove trailing zeros from scientific notation Number strings
- Update tests. This has the happy side effect of making some of the string
representations _more_ consistent between the small and large
mantissa ranges.
- Add semi-automatic rounding of STNumbers based on Asset types
- Create a new SField metadata enum, sMD_NeedsAsset, which indicates
the field should be associated with an Asset so it can be rounded.
- Add a new STTakesAsset intermediate class to handle the Asset
association to a derived ST class. Currently only used in STNumber,
but could be used by other types in the future.
- Add "associateAsset" which takes an SLE and an Asset, finds the
sMD_NeedsAsset fields, and associates the Asset to them. In the case
of STNumber, that both stores the Asset, and rounds the value
immediately.
- Transactors only need to add a call to associateAsset _after_ all of
the STNumbers have been set. Unfortunately, the inner workings of
STObject do not do the association correctly with uninitialized
fields.
- When serializing an STNumber that has an Asset, round it before
serializing.
- Add an override of roundToAsset, which rounds a Number value in place
to an Asset, but without any additional scale.
- Update and fix a bunch of Loan-related tests to accommodate the
expanded Number class.
---------
Co-authored-by: Vito <5780819+Tapanito@users.noreply.github.com>
219 lines
4.5 KiB
C++
219 lines
4.5 KiB
C++
#ifndef XRPL_BASICS_IOUAMOUNT_H_INCLUDED
|
|
#define XRPL_BASICS_IOUAMOUNT_H_INCLUDED
|
|
|
|
#include <xrpl/basics/LocalValue.h>
|
|
#include <xrpl/basics/Number.h>
|
|
#include <xrpl/beast/utility/Zero.h>
|
|
|
|
#include <boost/operators.hpp>
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
|
|
namespace xrpl {
|
|
|
|
/** Floating point representation of amounts with high dynamic range
|
|
|
|
Amounts are stored as a normalized signed mantissa and an exponent. The
|
|
range of the normalized exponent is [-96,80] and the range of the absolute
|
|
value of the normalized mantissa is [1000000000000000, 9999999999999999].
|
|
|
|
Arithmetic operations can throw std::overflow_error during normalization
|
|
if the amount exceeds the largest representable amount, but underflows
|
|
will silently truncate to zero.
|
|
*/
|
|
class IOUAmount : private boost::totally_ordered<IOUAmount>,
|
|
private boost::additive<IOUAmount>
|
|
{
|
|
private:
|
|
using mantissa_type = std::int64_t;
|
|
using exponent_type = int;
|
|
mantissa_type mantissa_;
|
|
exponent_type exponent_;
|
|
|
|
/** Adjusts the mantissa and exponent to the proper range.
|
|
|
|
This can throw if the amount cannot be normalized, or is larger than
|
|
the largest value that can be represented as an IOU amount. Amounts
|
|
that are too small to be represented normalize to 0.
|
|
*/
|
|
void
|
|
normalize();
|
|
|
|
static IOUAmount
|
|
fromNumber(Number const& number);
|
|
|
|
public:
|
|
IOUAmount() = default;
|
|
explicit IOUAmount(Number const& other);
|
|
IOUAmount(beast::Zero);
|
|
IOUAmount(mantissa_type mantissa, exponent_type exponent);
|
|
|
|
IOUAmount& operator=(beast::Zero);
|
|
|
|
operator Number() const;
|
|
|
|
IOUAmount&
|
|
operator+=(IOUAmount const& other);
|
|
|
|
IOUAmount&
|
|
operator-=(IOUAmount const& other);
|
|
|
|
IOUAmount
|
|
operator-() const;
|
|
|
|
bool
|
|
operator==(IOUAmount const& other) const;
|
|
|
|
bool
|
|
operator<(IOUAmount const& other) const;
|
|
|
|
/** Returns true if the amount is not zero */
|
|
explicit
|
|
operator bool() const noexcept;
|
|
|
|
/** Return the sign of the amount */
|
|
int
|
|
signum() const noexcept;
|
|
|
|
exponent_type
|
|
exponent() const noexcept;
|
|
|
|
mantissa_type
|
|
mantissa() const noexcept;
|
|
|
|
static IOUAmount
|
|
minPositiveAmount();
|
|
|
|
friend std::ostream&
|
|
operator<<(std::ostream& os, IOUAmount const& x)
|
|
{
|
|
return os << to_string(x);
|
|
}
|
|
};
|
|
|
|
inline IOUAmount::IOUAmount(beast::Zero)
|
|
{
|
|
*this = beast::zero;
|
|
}
|
|
|
|
inline IOUAmount::IOUAmount(mantissa_type mantissa, exponent_type exponent)
|
|
: mantissa_(mantissa), exponent_(exponent)
|
|
{
|
|
normalize();
|
|
}
|
|
|
|
inline IOUAmount&
|
|
IOUAmount::operator=(beast::Zero)
|
|
{
|
|
// The -100 is used to allow 0 to sort less than small positive values
|
|
// which will have a large negative exponent.
|
|
mantissa_ = 0;
|
|
exponent_ = -100;
|
|
return *this;
|
|
}
|
|
|
|
inline IOUAmount::operator Number() const
|
|
{
|
|
return Number{mantissa_, exponent_};
|
|
}
|
|
|
|
inline IOUAmount&
|
|
IOUAmount::operator-=(IOUAmount const& other)
|
|
{
|
|
*this += -other;
|
|
return *this;
|
|
}
|
|
|
|
inline IOUAmount
|
|
IOUAmount::operator-() const
|
|
{
|
|
return {-mantissa_, exponent_};
|
|
}
|
|
|
|
inline bool
|
|
IOUAmount::operator==(IOUAmount const& other) const
|
|
{
|
|
return exponent_ == other.exponent_ && mantissa_ == other.mantissa_;
|
|
}
|
|
|
|
inline bool
|
|
IOUAmount::operator<(IOUAmount const& other) const
|
|
{
|
|
return Number{*this} < Number{other};
|
|
}
|
|
|
|
inline IOUAmount::operator bool() const noexcept
|
|
{
|
|
return mantissa_ != 0;
|
|
}
|
|
|
|
inline int
|
|
IOUAmount::signum() const noexcept
|
|
{
|
|
return (mantissa_ < 0) ? -1 : (mantissa_ ? 1 : 0);
|
|
}
|
|
|
|
inline IOUAmount::exponent_type
|
|
IOUAmount::exponent() const noexcept
|
|
{
|
|
return exponent_;
|
|
}
|
|
|
|
inline IOUAmount::mantissa_type
|
|
IOUAmount::mantissa() const noexcept
|
|
{
|
|
return mantissa_;
|
|
}
|
|
|
|
std::string
|
|
to_string(IOUAmount const& amount);
|
|
|
|
/* Return num*amt/den
|
|
This function keeps more precision than computing
|
|
num*amt, storing the result in an IOUAmount, then
|
|
dividing by den.
|
|
*/
|
|
IOUAmount
|
|
mulRatio(
|
|
IOUAmount const& amt,
|
|
std::uint32_t num,
|
|
std::uint32_t den,
|
|
bool roundUp);
|
|
|
|
// Since many uses of the number class do not have access to a ledger,
|
|
// getSTNumberSwitchover needs to be globally accessible.
|
|
|
|
bool
|
|
getSTNumberSwitchover();
|
|
|
|
void
|
|
setSTNumberSwitchover(bool v);
|
|
|
|
/** RAII class to set and restore the Number switchover.
|
|
*/
|
|
|
|
class NumberSO
|
|
{
|
|
bool saved_;
|
|
|
|
public:
|
|
~NumberSO()
|
|
{
|
|
setSTNumberSwitchover(saved_);
|
|
}
|
|
|
|
NumberSO(NumberSO const&) = delete;
|
|
NumberSO&
|
|
operator=(NumberSO const&) = delete;
|
|
|
|
explicit NumberSO(bool v) : saved_(getSTNumberSwitchover())
|
|
{
|
|
setSTNumberSwitchover(v);
|
|
}
|
|
};
|
|
|
|
} // namespace xrpl
|
|
|
|
#endif
|