#pragma once #include #include #include #include #include #include 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, private boost::additive { 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 */ [[nodiscard]] int signum() const noexcept; [[nodiscard]] exponent_type exponent() const noexcept; [[nodiscard]] 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::kZero; } 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 { if (mantissa_ < 0) return -1; return (mantissa_ != 0) ? 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); } // namespace xrpl