mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Add IOU and XRP Amounts
This commit is contained in:
@@ -2552,6 +2552,8 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\protocol\AccountID.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\protocol\AmountSpec.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\protocol\Book.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\protocol\BuildInfo.h">
|
||||
|
||||
@@ -3099,6 +3099,9 @@
|
||||
<ClInclude Include="..\..\src\ripple\protocol\AccountID.h">
|
||||
<Filter>ripple\protocol</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\protocol\AmountSpec.h">
|
||||
<Filter>ripple\protocol</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\protocol\Book.h">
|
||||
<Filter>ripple\protocol</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/ledger/ReadView.h>
|
||||
#include <ripple/protocol/AmountSpec.h>
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
|
||||
@@ -48,6 +49,16 @@ creditLimit (
|
||||
return result;
|
||||
}
|
||||
|
||||
IOUAmount
|
||||
creditLimit2 (
|
||||
ReadView const& v,
|
||||
AccountID const& acc,
|
||||
AccountID const& iss,
|
||||
Currency const& cur)
|
||||
{
|
||||
return toAmount<IOUAmount> (creditLimit (v, acc, iss, cur));
|
||||
}
|
||||
|
||||
STAmount creditBalance (
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
@@ -72,4 +83,15 @@ STAmount creditBalance (
|
||||
return result;
|
||||
}
|
||||
|
||||
IOUAmount
|
||||
creditBalance2 (
|
||||
ReadView const& v,
|
||||
AccountID const& acc,
|
||||
AccountID const& iss,
|
||||
Currency const& cur)
|
||||
{
|
||||
return toAmount<IOUAmount> (creditBalance (v, acc, iss, cur));
|
||||
}
|
||||
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <ripple/protocol/IOUAmount.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -38,6 +39,13 @@ STAmount creditLimit (
|
||||
AccountID const& issuer,
|
||||
Currency const& currency);
|
||||
|
||||
IOUAmount
|
||||
creditLimit2 (
|
||||
ReadView const& v,
|
||||
AccountID const& acc,
|
||||
AccountID const& iss,
|
||||
Currency const& cur);
|
||||
|
||||
/** Returns the amount of IOUs issued by issuer that are held by an account
|
||||
@param ledger the ledger to check against.
|
||||
@param account the account of interest.
|
||||
@@ -50,6 +58,13 @@ STAmount creditBalance (
|
||||
AccountID const& issuer,
|
||||
Currency const& currency);
|
||||
|
||||
IOUAmount
|
||||
creditBalance2 (
|
||||
ReadView const& v,
|
||||
AccountID const& acc,
|
||||
AccountID const& iss,
|
||||
Currency const& cur);
|
||||
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_LEDGER_TESTS_PATHSET_H_INCLUDED
|
||||
#define RIPPLE_LEDGER_TESTS_PATHSET_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/test/jtx.h>
|
||||
@@ -134,3 +137,5 @@ private:
|
||||
|
||||
} // test
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
|
||||
289
src/ripple/protocol/AmountSpec.h
Normal file
289
src/ripple/protocol/AmountSpec.h
Normal file
@@ -0,0 +1,289 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_PROTOCOL_AMOUNTSPEC_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_AMOUNTSPEC_H_INCLUDED
|
||||
|
||||
#include <ripple/protocol/IOUAmount.h>
|
||||
#include <ripple/protocol/XRPAmount.h>
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
struct AmountSpec
|
||||
{
|
||||
bool native;
|
||||
union
|
||||
{
|
||||
XRPAmount xrp;
|
||||
IOUAmount iou;
|
||||
};
|
||||
boost::optional<AccountID> issuer;
|
||||
boost::optional<Currency> currency;
|
||||
|
||||
private:
|
||||
friend
|
||||
std::ostream&
|
||||
operator << (
|
||||
std::ostream& stream,
|
||||
AmountSpec const& amt)
|
||||
{
|
||||
if (amt.native)
|
||||
stream << to_string (amt.xrp);
|
||||
else
|
||||
stream << to_string (amt.iou);
|
||||
if (amt.currency)
|
||||
stream << "/(" << *amt.currency << ")";
|
||||
if (amt.issuer)
|
||||
stream << "/" << *amt.issuer << "";
|
||||
return stream;
|
||||
}
|
||||
};
|
||||
|
||||
struct EitherAmount
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
bool native = false;
|
||||
#endif
|
||||
|
||||
union
|
||||
{
|
||||
IOUAmount iou;
|
||||
XRPAmount xrp;
|
||||
};
|
||||
|
||||
EitherAmount () = default;
|
||||
|
||||
explicit
|
||||
EitherAmount (IOUAmount const& a)
|
||||
:iou(a)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
// ignore warning about half of iou amount being uninitialized
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
explicit
|
||||
EitherAmount (XRPAmount const& a)
|
||||
:xrp(a)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
native = true;
|
||||
#endif
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
explicit
|
||||
EitherAmount (AmountSpec const& a)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
native = a.native;
|
||||
#endif
|
||||
if (a.native)
|
||||
xrp = a.xrp;
|
||||
else
|
||||
iou = a.iou;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T&
|
||||
get (EitherAmount& amt)
|
||||
{
|
||||
static_assert(sizeof(T) == -1, "Must used specialized function");
|
||||
return T(0);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
IOUAmount&
|
||||
get<IOUAmount> (EitherAmount& amt)
|
||||
{
|
||||
assert (!amt.native);
|
||||
return amt.iou;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
XRPAmount&
|
||||
get<XRPAmount> (EitherAmount& amt)
|
||||
{
|
||||
assert (amt.native);
|
||||
return amt.xrp;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T const&
|
||||
get (EitherAmount const& amt)
|
||||
{
|
||||
static_assert(sizeof(T) == -1, "Must used specialized function");
|
||||
return T(0);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
IOUAmount const&
|
||||
get<IOUAmount> (EitherAmount const& amt)
|
||||
{
|
||||
assert (!amt.native);
|
||||
return amt.iou;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
XRPAmount const&
|
||||
get<XRPAmount> (EitherAmount const& amt)
|
||||
{
|
||||
assert (amt.native);
|
||||
return amt.xrp;
|
||||
}
|
||||
|
||||
inline
|
||||
AmountSpec
|
||||
toAmountSpec (STAmount const& amt)
|
||||
{
|
||||
assert (amt.mantissa () < std::numeric_limits<std::int64_t>::max ());
|
||||
bool const isNeg = amt.negative ();
|
||||
std::int64_t const sMant =
|
||||
isNeg ? - std::int64_t (amt.mantissa ()) : amt.mantissa ();
|
||||
AmountSpec result;
|
||||
|
||||
result.native = isXRP (amt);
|
||||
if (result.native)
|
||||
{
|
||||
result.xrp = XRPAmount (sMant);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.iou = IOUAmount (sMant, amt.exponent ());
|
||||
result.issuer = amt.issue().account;
|
||||
result.currency = amt.issue().currency;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
AmountSpec
|
||||
toAmountSpec (
|
||||
EitherAmount const& ea,
|
||||
boost::optional<Currency> const& c)
|
||||
{
|
||||
AmountSpec r;
|
||||
r.native = (!c || isXRP (*c));
|
||||
r.currency = c;
|
||||
assert (ea.native == r.native);
|
||||
if (r.native)
|
||||
{
|
||||
r.xrp = ea.xrp;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.iou = ea.iou;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
STAmount
|
||||
toSTAmount (IOUAmount const& iou, Issue const& iss)
|
||||
{
|
||||
bool const isNeg = iou.signum() < 0;
|
||||
std::uint64_t const umant = isNeg ? - iou.mantissa () : iou.mantissa ();
|
||||
return STAmount (iss, umant, iou.exponent (), /*native*/ false, isNeg,
|
||||
STAmount::unchecked ());
|
||||
}
|
||||
|
||||
inline
|
||||
STAmount
|
||||
toSTAmount (IOUAmount const& iou)
|
||||
{
|
||||
return toSTAmount (iou, noIssue ());
|
||||
}
|
||||
|
||||
inline
|
||||
STAmount
|
||||
toSTAmount (XRPAmount const& xrp)
|
||||
{
|
||||
bool const isNeg = xrp.signum() < 0;
|
||||
std::uint64_t const umant = isNeg ? - xrp.drops () : xrp.drops ();
|
||||
return STAmount (umant, isNeg);
|
||||
}
|
||||
|
||||
inline
|
||||
STAmount
|
||||
toSTAmount (XRPAmount const& xrp, Issue const& iss)
|
||||
{
|
||||
assert (isXRP(iss.account) && isXRP(iss.currency));
|
||||
return toSTAmount (xrp);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T
|
||||
toAmount (STAmount const& amt)
|
||||
{
|
||||
static_assert(sizeof(T) == -1, "Must used specialized function");
|
||||
return T(0);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
STAmount
|
||||
toAmount<STAmount> (STAmount const& amt)
|
||||
{
|
||||
return amt;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
IOUAmount
|
||||
toAmount<IOUAmount> (STAmount const& amt)
|
||||
{
|
||||
assert (amt.mantissa () < std::numeric_limits<std::int64_t>::max ());
|
||||
bool const isNeg = amt.negative ();
|
||||
std::int64_t const sMant =
|
||||
isNeg ? - std::int64_t (amt.mantissa ()) : amt.mantissa ();
|
||||
|
||||
assert (! isXRP (amt));
|
||||
return IOUAmount (sMant, amt.exponent ());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
XRPAmount
|
||||
toAmount<XRPAmount> (STAmount const& amt)
|
||||
{
|
||||
assert (amt.mantissa () < std::numeric_limits<std::int64_t>::max ());
|
||||
bool const isNeg = amt.negative ();
|
||||
std::int64_t const sMant =
|
||||
isNeg ? - std::int64_t (amt.mantissa ()) : amt.mantissa ();
|
||||
AmountSpec result;
|
||||
|
||||
assert (isXRP (amt));
|
||||
return XRPAmount (sMant);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -140,6 +140,13 @@ public:
|
||||
std::string
|
||||
to_string (IOUAmount const& amount);
|
||||
|
||||
IOUAmount
|
||||
mulRatio (
|
||||
IOUAmount const& amt,
|
||||
std::uint32_t num,
|
||||
std::uint32_t den,
|
||||
bool roundUp);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,11 @@
|
||||
#ifndef RIPPLE_PROTOCOL_QUALITY_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_QUALITY_H_INCLUDED
|
||||
|
||||
#include <ripple/protocol/AmountSpec.h>
|
||||
#include <ripple/protocol/IOUAmount.h>
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <ripple/protocol/XRPAmount.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
|
||||
@@ -35,11 +39,18 @@ namespace ripple {
|
||||
For offers, "in" is always TakerPays and "out" is
|
||||
always TakerGets.
|
||||
*/
|
||||
struct Amounts
|
||||
template<class TIn, class TOut>
|
||||
struct TAmounts
|
||||
{
|
||||
Amounts() = default;
|
||||
TAmounts() = default;
|
||||
|
||||
Amounts (STAmount const& in_, STAmount const& out_)
|
||||
TAmounts (beast::Zero, beast::Zero)
|
||||
: in (beast::zero)
|
||||
, out (beast::zero)
|
||||
{
|
||||
}
|
||||
|
||||
TAmounts (TIn const& in_, TOut const& out_)
|
||||
: in (in_)
|
||||
, out (out_)
|
||||
{
|
||||
@@ -52,20 +63,46 @@ struct Amounts
|
||||
return in <= zero || out <= zero;
|
||||
}
|
||||
|
||||
STAmount in;
|
||||
STAmount out;
|
||||
TAmounts& operator+=(TAmounts const& rhs)
|
||||
{
|
||||
in += rhs.in;
|
||||
out += rhs.out;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TAmounts& operator-=(TAmounts const& rhs)
|
||||
{
|
||||
in -= rhs.in;
|
||||
out -= rhs.out;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TIn in;
|
||||
TOut out;
|
||||
};
|
||||
|
||||
inline
|
||||
template<class TIn, class TOut>
|
||||
TAmounts<TIn, TOut> make_Amounts(TIn const& in, TOut const& out)
|
||||
{
|
||||
return TAmounts<TIn, TOut>(in, out);
|
||||
}
|
||||
|
||||
using Amounts = TAmounts<STAmount, STAmount>;
|
||||
|
||||
template<class TIn, class TOut>
|
||||
bool
|
||||
operator== (Amounts const& lhs, Amounts const& rhs) noexcept
|
||||
operator== (
|
||||
TAmounts<TIn, TOut> const& lhs,
|
||||
TAmounts<TIn, TOut> const& rhs) noexcept
|
||||
{
|
||||
return lhs.in == rhs.in && lhs.out == rhs.out;
|
||||
}
|
||||
|
||||
inline
|
||||
template<class TIn, class TOut>
|
||||
bool
|
||||
operator!= (Amounts const& lhs, Amounts const& rhs) noexcept
|
||||
operator!= (
|
||||
TAmounts<TIn, TOut> const& lhs,
|
||||
TAmounts<TIn, TOut> const& rhs) noexcept
|
||||
{
|
||||
return ! (lhs == rhs);
|
||||
}
|
||||
@@ -101,6 +138,13 @@ public:
|
||||
explicit
|
||||
Quality (Amounts const& amount);
|
||||
|
||||
/** Create a quality from the ratio of two amounts. */
|
||||
template<class TIn, class TOut>
|
||||
Quality (TOut const& out, TIn const& in)
|
||||
: Quality (Amounts (toSTAmount (in),
|
||||
toSTAmount (out)))
|
||||
{}
|
||||
|
||||
/** Advances to the next higher quality level. */
|
||||
/** @{ */
|
||||
Quality&
|
||||
@@ -133,6 +177,21 @@ public:
|
||||
Amounts
|
||||
ceil_in (Amounts const& amount, STAmount const& limit) const;
|
||||
|
||||
template<class TIn, class TOut>
|
||||
TAmounts<TIn, TOut>
|
||||
ceil_in (TAmounts<TIn, TOut> const& amount, TIn const& limit) const
|
||||
{
|
||||
if (amount.in <= limit)
|
||||
return amount;
|
||||
|
||||
// Use the existing STAmount implementation for now, but consider
|
||||
// replacing with code specific to IOUAMount and XRPAmount
|
||||
Amounts stAmt (toSTAmount (amount.in), toSTAmount (amount.out));
|
||||
STAmount stLim (toSTAmount (limit));
|
||||
auto const stRes = ceil_in (stAmt, stLim);
|
||||
return TAmounts<TIn, TOut> (toAmount<TIn> (stRes.in), toAmount<TOut> (stRes.out));
|
||||
}
|
||||
|
||||
/** Returns the scaled amount with out capped.
|
||||
Math is avoided if the result is exact. The input is clamped
|
||||
to prevent money creation.
|
||||
@@ -140,6 +199,21 @@ public:
|
||||
Amounts
|
||||
ceil_out (Amounts const& amount, STAmount const& limit) const;
|
||||
|
||||
template<class TIn, class TOut>
|
||||
TAmounts<TIn, TOut>
|
||||
ceil_out (TAmounts<TIn, TOut> const& amount, TOut const& limit) const
|
||||
{
|
||||
if (amount.out <= limit)
|
||||
return amount;
|
||||
|
||||
// Use the existing STAmount implementation for now, but consider
|
||||
// replacing with code specific to IOUAMount and XRPAmount
|
||||
Amounts stAmt (toSTAmount (amount.in), toSTAmount (amount.out));
|
||||
STAmount stLim (toSTAmount (limit));
|
||||
auto const stRes = ceil_out (stAmt, stLim);
|
||||
return TAmounts<TIn, TOut> (toAmount<TIn> (stRes.in), toAmount<TOut> (stRes.out));
|
||||
}
|
||||
|
||||
/** Returns `true` if lhs is lower quality than `rhs`.
|
||||
Lower quality means the taker receives a worse deal.
|
||||
Higher quality is better for the taker.
|
||||
@@ -151,6 +225,13 @@ public:
|
||||
return lhs.m_value > rhs.m_value;
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
operator> (Quality const& lhs, Quality const& rhs) noexcept
|
||||
{
|
||||
return lhs.m_value < rhs.m_value;
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
operator== (Quality const& lhs, Quality const& rhs) noexcept
|
||||
|
||||
@@ -312,6 +312,15 @@ amountFromJson (SField const& name, Json::Value const& v);
|
||||
bool
|
||||
amountFromJsonNoThrow (STAmount& result, Json::Value const& jvSource);
|
||||
|
||||
// IOUAmount and XRPAmount define toSTAmount, defining this
|
||||
// trivial conversion here makes writing generic code easier
|
||||
inline
|
||||
STAmount const&
|
||||
toSTAmount (STAmount const& a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Observers
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/protocol/SystemParameters.h>
|
||||
#include <beast/utility/Zero.h>
|
||||
#include <boost/operators.hpp>
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
@@ -134,6 +135,27 @@ to_string (XRPAmount const& amount)
|
||||
return std::to_string (amount.drops ());
|
||||
}
|
||||
|
||||
inline
|
||||
XRPAmount
|
||||
mulRatio (
|
||||
XRPAmount const& amt,
|
||||
std::uint32_t num,
|
||||
std::uint32_t den,
|
||||
bool roundUp)
|
||||
{
|
||||
using namespace boost::multiprecision;
|
||||
int128_t const den128 (den);
|
||||
int128_t const num128 (num);
|
||||
int128_t const amt128 (amt.drops ());
|
||||
auto const m = int128_t (amt.drops ()) * num;
|
||||
auto r = m / den;
|
||||
if (roundUp && r >= 0 && (m % den))
|
||||
r += 1;
|
||||
if (r > std::numeric_limits<std::int64_t>::max ())
|
||||
throw std::overflow_error ("XRP mulRatio overflow");
|
||||
return XRPAmount (r.convert_to<std::int64_t> ());
|
||||
}
|
||||
|
||||
/** Returns true if the amount does not exceed the initial XRP in existence. */
|
||||
inline
|
||||
bool isLegalAmount (XRPAmount const& amount)
|
||||
|
||||
@@ -20,23 +20,24 @@
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/protocol/IOUAmount.h>
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/* The range for the mantissa when normalized */
|
||||
static std::int64_t const minMantissa = 1000000000000000ull;
|
||||
static std::int64_t const maxMantissa = 9999999999999999ull;
|
||||
/* The range for the exponent when normalized */
|
||||
static int const minExponent = -96;
|
||||
static int const maxExponent = 80;
|
||||
|
||||
void
|
||||
IOUAmount::normalize ()
|
||||
{
|
||||
/* The range for the exponent when normalized */
|
||||
static int const minExponent = -96;
|
||||
static int const maxExponent = 80;
|
||||
|
||||
/* The range for the mantissa when normalized */
|
||||
static std::int64_t const minMantissa = 1000000000000000ull;
|
||||
static std::int64_t const maxMantissa = 9999999999999999ull;
|
||||
|
||||
if (mantissa_ == 0)
|
||||
{
|
||||
*this = zero;
|
||||
@@ -244,4 +245,96 @@ to_string (IOUAmount const& amount)
|
||||
return ret;
|
||||
}
|
||||
|
||||
IOUAmount
|
||||
mulRatio (
|
||||
IOUAmount const& amt,
|
||||
std::uint32_t num,
|
||||
std::uint32_t den,
|
||||
bool roundUp)
|
||||
{
|
||||
using namespace boost::multiprecision;
|
||||
|
||||
static std::vector<uint128_t> const logTable = []
|
||||
{
|
||||
std::vector<uint128_t> result;
|
||||
result.reserve (30); // 2^96 is largest intermediate result size
|
||||
uint128_t cur (1);
|
||||
for (int i = 0; i < 30; ++i)
|
||||
{
|
||||
result.push_back (cur);
|
||||
cur *= 10;
|
||||
};
|
||||
return result;
|
||||
}();
|
||||
// Note: Returns -1 for v == 0
|
||||
static auto log10Floor = [](uint128_t const& v)
|
||||
{
|
||||
auto const l = std::lower_bound (logTable.begin (), logTable.end (), v);
|
||||
int index = std::distance (logTable.begin (), l);
|
||||
if (*l != v)
|
||||
--index;
|
||||
return index;
|
||||
};
|
||||
static auto log10Ceil = [](uint128_t const& v)
|
||||
{
|
||||
auto const l = std::lower_bound (logTable.begin (), logTable.end (), v);
|
||||
return int(std::distance (logTable.begin (), l));
|
||||
};
|
||||
static auto const fl64 =
|
||||
log10Floor (std::numeric_limits<std::int64_t>::max ());
|
||||
bool const neg = amt.mantissa () < 0;
|
||||
uint128_t const den128 (den);
|
||||
uint128_t const mul =
|
||||
uint128_t (neg ? -amt.mantissa () : amt.mantissa ()) * uint128_t (num);
|
||||
auto low = mul / den128;
|
||||
uint128_t rem (mul - low * den128);
|
||||
|
||||
int exponent = amt.exponent ();
|
||||
|
||||
if (rem)
|
||||
{
|
||||
auto const roomToGrow = fl64 - log10Ceil (low);
|
||||
if (roomToGrow > 0)
|
||||
{
|
||||
exponent -= roomToGrow;
|
||||
low *= logTable[roomToGrow];
|
||||
rem *= logTable[roomToGrow];
|
||||
}
|
||||
auto const addRem = rem / den128;
|
||||
low += addRem;
|
||||
rem = rem - addRem * den128;
|
||||
}
|
||||
|
||||
bool hasRem = bool(rem);
|
||||
auto const mustShrink = log10Ceil (low) - fl64;
|
||||
if (mustShrink > 0)
|
||||
{
|
||||
uint128_t const sav (low);
|
||||
exponent += mustShrink;
|
||||
low /= logTable[mustShrink];
|
||||
if (!hasRem && roundUp)
|
||||
hasRem = bool(sav - low * logTable[mustShrink]);
|
||||
}
|
||||
|
||||
std::int64_t mantissa = low.convert_to<std::int64_t> ();
|
||||
|
||||
// normalize before rounding
|
||||
if (neg)
|
||||
mantissa *= -1;
|
||||
|
||||
IOUAmount result (mantissa, exponent);
|
||||
|
||||
if (roundUp && hasRem && !neg)
|
||||
{
|
||||
if (!result)
|
||||
{
|
||||
return IOUAmount (minMantissa, minExponent);
|
||||
}
|
||||
return IOUAmount (result.mantissa() + 1, result.exponent());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user