rippled
IOUAmount.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/IOUAmount.h>
21 #include <ripple/basics/contract.h>
22 #include <boost/multiprecision/cpp_int.hpp>
23 #include <algorithm>
24 #include <iterator>
25 #include <numeric>
26 #include <stdexcept>
27 
28 namespace ripple {
29 
30 LocalValue<bool> stNumberSwitchover(true);
31 
32 /* The range for the mantissa when normalized */
33 static std::int64_t constexpr minMantissa = 1000000000000000ull;
34 static std::int64_t constexpr maxMantissa = 9999999999999999ull;
35 /* The range for the exponent when normalized */
36 static int constexpr minExponent = -96;
37 static int constexpr maxExponent = 80;
38 
41 {
43 }
44 
45 void
47 {
48  if (mantissa_ == 0)
49  {
50  *this = beast::zero;
51  return;
52  }
53 
54  if (*stNumberSwitchover)
55  {
56  Number const v{mantissa_, exponent_};
57  mantissa_ = v.mantissa();
58  exponent_ = v.exponent();
59  if (exponent_ > maxExponent)
60  Throw<std::overflow_error>("value overflow");
61  if (exponent_ < minExponent)
62  *this = beast::zero;
63  return;
64  }
65 
66  bool const negative = (mantissa_ < 0);
67 
68  if (negative)
70 
71  while ((mantissa_ < minMantissa) && (exponent_ > minExponent))
72  {
73  mantissa_ *= 10;
74  --exponent_;
75  }
76 
77  while (mantissa_ > maxMantissa)
78  {
79  if (exponent_ >= maxExponent)
80  Throw<std::overflow_error>("IOUAmount::normalize");
81 
82  mantissa_ /= 10;
83  ++exponent_;
84  }
85 
87  {
88  *this = beast::zero;
89  return;
90  }
91 
92  if (exponent_ > maxExponent)
93  Throw<std::overflow_error>("value overflow");
94 
95  if (negative)
97 }
98 
100  : mantissa_(other.mantissa()), exponent_(other.exponent())
101 {
102  if (exponent_ > maxExponent)
103  Throw<std::overflow_error>("value overflow");
104  if (exponent_ < minExponent)
105  *this = beast::zero;
106 }
107 
108 IOUAmount&
110 {
111  if (other == beast::zero)
112  return *this;
113 
114  if (*this == beast::zero)
115  {
116  *this = other;
117  return *this;
118  }
119 
120  if (*stNumberSwitchover)
121  {
122  *this = IOUAmount{Number{*this} + Number{other}};
123  return *this;
124  }
125  auto m = other.mantissa_;
126  auto e = other.exponent_;
127 
128  while (exponent_ < e)
129  {
130  mantissa_ /= 10;
131  ++exponent_;
132  }
133 
134  while (e < exponent_)
135  {
136  m /= 10;
137  ++e;
138  }
139 
140  // This addition cannot overflow an std::int64_t but we may throw from
141  // normalize if the result isn't representable.
142  mantissa_ += m;
143 
144  if (mantissa_ >= -10 && mantissa_ <= 10)
145  {
146  *this = beast::zero;
147  return *this;
148  }
149 
150  normalize();
151  return *this;
152 }
153 
155 to_string(IOUAmount const& amount)
156 {
157  return to_string(Number{amount});
158 }
159 
160 IOUAmount
162  IOUAmount const& amt,
163  std::uint32_t num,
164  std::uint32_t den,
165  bool roundUp)
166 {
167  using namespace boost::multiprecision;
168 
169  if (!den)
170  Throw<std::runtime_error>("division by zero");
171 
172  // A vector with the value 10^index for indexes from 0 to 29
173  // The largest intermediate value we expect is 2^96, which
174  // is less than 10^29
175  static auto const powerTable = [] {
176  std::vector<uint128_t> result;
177  result.reserve(30); // 2^96 is largest intermediate result size
178  uint128_t cur(1);
179  for (int i = 0; i < 30; ++i)
180  {
181  result.push_back(cur);
182  cur *= 10;
183  };
184  return result;
185  }();
186 
187  // Return floor(log10(v))
188  // Note: Returns -1 for v == 0
189  static auto log10Floor = [](uint128_t const& v) {
190  // Find the index of the first element >= the requested element, the
191  // index is the log of the element in the log table.
192  auto const l =
193  std::lower_bound(powerTable.begin(), powerTable.end(), v);
194  int index = std::distance(powerTable.begin(), l);
195  // If we're not equal, subtract to get the floor
196  if (*l != v)
197  --index;
198  return index;
199  };
200 
201  // Return ceil(log10(v))
202  static auto log10Ceil = [](uint128_t const& v) {
203  // Find the index of the first element >= the requested element, the
204  // index is the log of the element in the log table.
205  auto const l =
206  std::lower_bound(powerTable.begin(), powerTable.end(), v);
207  return int(std::distance(powerTable.begin(), l));
208  };
209 
210  static auto const fl64 =
212 
213  bool const neg = amt.mantissa() < 0;
214  uint128_t const den128(den);
215  // a 32 value * a 64 bit value and stored in a 128 bit value. This will
216  // never overflow
217  uint128_t const mul =
218  uint128_t(neg ? -amt.mantissa() : amt.mantissa()) * uint128_t(num);
219 
220  auto low = mul / den128;
221  uint128_t rem(mul - low * den128);
222 
223  int exponent = amt.exponent();
224 
225  if (rem)
226  {
227  // Mathematically, the result is low + rem/den128. However, since this
228  // uses integer division rem/den128 will be zero. Scale the result so
229  // low does not overflow the largest amount we can store in the mantissa
230  // and (rem/den128) is as large as possible. Scale by multiplying low
231  // and rem by 10 and subtracting one from the exponent. We could do this
232  // with a loop, but it's more efficient to use logarithms.
233  auto const roomToGrow = fl64 - log10Ceil(low);
234  if (roomToGrow > 0)
235  {
236  exponent -= roomToGrow;
237  low *= powerTable[roomToGrow];
238  rem *= powerTable[roomToGrow];
239  }
240  auto const addRem = rem / den128;
241  low += addRem;
242  rem = rem - addRem * den128;
243  }
244 
245  // The largest result we can have is ~2^95, which overflows the 64 bit
246  // result we can store in the mantissa. Scale result down by dividing by ten
247  // and adding one to the exponent until the low will fit in the 64-bit
248  // mantissa. Use logarithms to avoid looping.
249  bool hasRem = bool(rem);
250  auto const mustShrink = log10Ceil(low) - fl64;
251  if (mustShrink > 0)
252  {
253  uint128_t const sav(low);
254  exponent += mustShrink;
255  low /= powerTable[mustShrink];
256  if (!hasRem)
257  hasRem = bool(sav - low * powerTable[mustShrink]);
258  }
259 
260  std::int64_t mantissa = low.convert_to<std::int64_t>();
261 
262  // normalize before rounding
263  if (neg)
264  mantissa *= -1;
265 
266  IOUAmount result(mantissa, exponent);
267 
268  if (hasRem)
269  {
270  // handle rounding
271  if (roundUp && !neg)
272  {
273  if (!result)
274  {
276  }
277  // This addition cannot overflow because the mantissa is already
278  // normalized
279  return IOUAmount(result.mantissa() + 1, result.exponent());
280  }
281 
282  if (!roundUp && neg)
283  {
284  if (!result)
285  {
287  }
288  // This subtraction cannot underflow because `result` is not zero
289  return IOUAmount(result.mantissa() - 1, result.exponent());
290  }
291  }
292 
293  return result;
294 }
295 
296 } // namespace ripple
ripple::mulRatio
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
Definition: IOUAmount.cpp:161
ripple::IOUAmount::exponent
int exponent() const noexcept
Definition: IOUAmount.h:163
ripple::maxExponent
static constexpr int maxExponent
Definition: IOUAmount.cpp:37
std::string
STL class.
ripple::IOUAmount::minPositiveAmount
static IOUAmount minPositiveAmount()
Definition: IOUAmount.cpp:40
std::vector::reserve
T reserve(T... args)
ripple::IOUAmount::normalize
void normalize()
Adjusts the mantissa and exponent to the proper range.
Definition: IOUAmount.cpp:46
std::vector
STL class.
iterator
std::distance
T distance(T... args)
ripple::IOUAmount
Floating point representation of amounts with high dynamic range.
Definition: IOUAmount.h:43
algorithm
std::vector::push_back
T push_back(T... args)
stdexcept
ripple::Number
Definition: Number.h:36
ripple::IOUAmount::mantissa_
std::int64_t mantissa_
Definition: IOUAmount.h:47
ripple::IOUAmount::exponent_
int exponent_
Definition: IOUAmount.h:48
ripple::maxMantissa
static constexpr std::int64_t maxMantissa
Definition: IOUAmount.cpp:34
ripple::minExponent
static constexpr int minExponent
Definition: IOUAmount.cpp:36
ripple::IOUAmount::IOUAmount
IOUAmount()=default
std::int64_t
ripple::IOUAmount::operator+=
IOUAmount & operator+=(IOUAmount const &other)
Definition: IOUAmount.cpp:109
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::IOUAmount::mantissa
std::int64_t mantissa() const noexcept
Definition: IOUAmount.h:169
std::lower_bound
T lower_bound(T... args)
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
numeric
ripple::stNumberSwitchover
LocalValue< bool > stNumberSwitchover(true)
Definition: IOUAmount.h:189
std::numeric_limits
ripple::minMantissa
static constexpr std::int64_t minMantissa
Definition: IOUAmount.cpp:33