rippled
Loading...
Searching...
No Matches
Number.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2022 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#ifndef RIPPLE_BASICS_NUMBER_H_INCLUDED
21#define RIPPLE_BASICS_NUMBER_H_INCLUDED
22
23#include <cstdint>
24#include <limits>
25#include <ostream>
26#include <string>
27
28namespace ripple {
29
30class Number;
31
33to_string(Number const& amount);
34
35class Number
36{
40
41public:
42 // The range for the mantissa when normalized
43 constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL;
44 constexpr static std::int64_t maxMantissa = 9'999'999'999'999'999LL;
45
46 // The range for the exponent when normalized
47 constexpr static int minExponent = -32768;
48 constexpr static int maxExponent = 32768;
49
50 struct unchecked
51 {
52 explicit unchecked() = default;
53 };
54
55 explicit constexpr Number() = default;
56
58 explicit Number(rep mantissa, int exponent);
59 explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept;
60
61 constexpr rep
62 mantissa() const noexcept;
63 constexpr int
64 exponent() const noexcept;
65
66 constexpr Number
67 operator+() const noexcept;
68 constexpr Number
69 operator-() const noexcept;
70 Number&
71 operator++();
72 Number
73 operator++(int);
74 Number&
75 operator--();
76 Number
77 operator--(int);
78
79 Number&
80 operator+=(Number const& x);
81 Number&
82 operator-=(Number const& x);
83
84 Number&
85 operator*=(Number const& x);
86 Number&
87 operator/=(Number const& x);
88
89 static constexpr Number
90 min() noexcept;
91 static constexpr Number
92 max() noexcept;
93 static constexpr Number
94 lowest() noexcept;
95
101 explicit
102 operator rep() const; // round to nearest, even on tie
103
104 friend constexpr bool
105 operator==(Number const& x, Number const& y) noexcept
106 {
107 return x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_;
108 }
109
110 friend constexpr bool
111 operator!=(Number const& x, Number const& y) noexcept
112 {
113 return !(x == y);
114 }
115
116 friend constexpr bool
117 operator<(Number const& x, Number const& y) noexcept
118 {
119 // If the two amounts have different signs (zero is treated as positive)
120 // then the comparison is true iff the left is negative.
121 bool const lneg = x.mantissa_ < 0;
122 bool const rneg = y.mantissa_ < 0;
123
124 if (lneg != rneg)
125 return lneg;
126
127 // Both have same sign and the left is zero: the right must be
128 // greater than 0.
129 if (x.mantissa_ == 0)
130 return y.mantissa_ > 0;
131
132 // Both have same sign, the right is zero and the left is non-zero.
133 if (y.mantissa_ == 0)
134 return false;
135
136 // Both have the same sign, compare by exponents:
137 if (x.exponent_ > y.exponent_)
138 return lneg;
139 if (x.exponent_ < y.exponent_)
140 return !lneg;
141
142 // If equal exponents, compare mantissas
143 return x.mantissa_ < y.mantissa_;
144 }
145
147 constexpr int
148 signum() const noexcept
149 {
150 return (mantissa_ < 0) ? -1 : (mantissa_ ? 1 : 0);
151 }
152
153 Number
154 truncate() const noexcept
155 {
156 if (exponent_ >= 0 || mantissa_ == 0)
157 return *this;
158
159 Number ret = *this;
160 while (ret.exponent_ < 0 && ret.mantissa_ != 0)
161 {
162 ret.exponent_ += 1;
163 ret.mantissa_ /= rep(10);
164 }
165 // We are guaranteed that normalize() will never throw an exception
166 // because exponent is either negative or zero at this point.
167 ret.normalize();
168 return ret;
169 }
170
171 friend constexpr bool
172 operator>(Number const& x, Number const& y) noexcept
173 {
174 return y < x;
175 }
176
177 friend constexpr bool
178 operator<=(Number const& x, Number const& y) noexcept
179 {
180 return !(y < x);
181 }
182
183 friend constexpr bool
184 operator>=(Number const& x, Number const& y) noexcept
185 {
186 return !(x < y);
187 }
188
190 operator<<(std::ostream& os, Number const& x)
191 {
192 return os << to_string(x);
193 }
194
195 // Thread local rounding control. Default is to_nearest
197 static rounding_mode
198 getround();
199 // Returns previously set mode
200 static rounding_mode
202
203private:
204 static thread_local rounding_mode mode_;
205
206 void
207 normalize();
208 constexpr bool
209 isnormal() const noexcept;
210
211 class Guard;
212};
213
214inline constexpr Number::Number(rep mantissa, int exponent, unchecked) noexcept
216{
217}
218
224
225inline Number::Number(rep mantissa) : Number{mantissa, 0}
226{
227}
228
229inline constexpr Number::rep
230Number::mantissa() const noexcept
231{
232 return mantissa_;
233}
234
235inline constexpr int
236Number::exponent() const noexcept
237{
238 return exponent_;
239}
240
241inline constexpr Number
242Number::operator+() const noexcept
243{
244 return *this;
245}
246
247inline constexpr Number
248Number::operator-() const noexcept
249{
250 auto x = *this;
251 x.mantissa_ = -x.mantissa_;
252 return x;
253}
254
255inline Number&
257{
258 *this += Number{1000000000000000, -15, unchecked{}};
259 return *this;
260}
261
262inline Number
264{
265 auto x = *this;
266 ++(*this);
267 return x;
268}
269
270inline Number&
272{
273 *this -= Number{1000000000000000, -15, unchecked{}};
274 return *this;
275}
276
277inline Number
279{
280 auto x = *this;
281 --(*this);
282 return x;
283}
284
285inline Number&
287{
288 return *this += -x;
289}
290
291inline Number
292operator+(Number const& x, Number const& y)
293{
294 auto z = x;
295 z += y;
296 return z;
297}
298
299inline Number
300operator-(Number const& x, Number const& y)
301{
302 auto z = x;
303 z -= y;
304 return z;
305}
306
307inline Number
308operator*(Number const& x, Number const& y)
309{
310 auto z = x;
311 z *= y;
312 return z;
313}
314
315inline Number
316operator/(Number const& x, Number const& y)
317{
318 auto z = x;
319 z /= y;
320 return z;
321}
322
323inline constexpr Number
324Number::min() noexcept
325{
327}
328
329inline constexpr Number
330Number::max() noexcept
331{
333}
334
335inline constexpr Number
337{
339}
340
341inline constexpr bool
342Number::isnormal() const noexcept
343{
344 auto const abs_m = mantissa_ < 0 ? -mantissa_ : mantissa_;
345 return minMantissa <= abs_m && abs_m <= maxMantissa &&
347}
348
349inline constexpr Number
350abs(Number x) noexcept
351{
352 if (x < Number{})
353 x = -x;
354 return x;
355}
356
357// Returns f^n
358// Uses a log_2(n) number of multiplications
359
360Number
361power(Number const& f, unsigned n);
362
363// Returns f^(1/d)
364// Uses Newton–Raphson iterations until the result stops changing
365// to find the root of the polynomial g(x) = x^d - f
366
367Number
368root(Number f, unsigned d);
369
370Number
371root2(Number f);
372
373// Returns f^(n/d)
374
375Number
376power(Number const& f, unsigned n, unsigned d);
377
378// Return 0 if abs(x) < limit, else returns x
379
380inline constexpr Number
381squelch(Number const& x, Number const& limit) noexcept
382{
383 if (abs(x) < limit)
384 return Number{};
385 return x;
386}
387
405
406// saveNumberRoundMode doesn't do quite enough for us. What we want is a
407// Number::RoundModeGuard that sets the new mode and restores the old mode
408// when it leaves scope. Since Number doesn't have that facility, we'll
409// build it here.
425
426} // namespace ripple
427
428#endif // RIPPLE_BASICS_NUMBER_H_INCLUDED
NumberRoundModeGuard(NumberRoundModeGuard const &)=delete
NumberRoundModeGuard & operator=(NumberRoundModeGuard const &)=delete
saveNumberRoundMode saved_
Definition Number.h:412
NumberRoundModeGuard(Number::rounding_mode mode) noexcept
Definition Number.h:415
constexpr bool isnormal() const noexcept
Definition Number.h:342
friend constexpr bool operator<(Number const &x, Number const &y) noexcept
Definition Number.h:117
static constexpr std::int64_t maxMantissa
Definition Number.h:44
Number & operator--()
Definition Number.h:271
static constexpr int maxExponent
Definition Number.h:48
Number truncate() const noexcept
Definition Number.h:154
static constexpr std::int64_t minMantissa
Definition Number.h:43
constexpr int exponent() const noexcept
Definition Number.h:236
static thread_local rounding_mode mode_
Definition Number.h:204
constexpr Number operator+() const noexcept
Definition Number.h:242
void normalize()
Definition Number.cpp:178
static constexpr Number max() noexcept
Definition Number.h:330
int exponent_
Definition Number.h:39
static rounding_mode getround()
Definition Number.cpp:47
Number & operator++()
Definition Number.h:256
static constexpr int minExponent
Definition Number.h:47
friend constexpr bool operator!=(Number const &x, Number const &y) noexcept
Definition Number.h:111
std::int64_t rep
Definition Number.h:37
friend constexpr bool operator>=(Number const &x, Number const &y) noexcept
Definition Number.h:184
static rounding_mode setround(rounding_mode mode)
Definition Number.cpp:53
constexpr rep mantissa() const noexcept
Definition Number.h:230
static constexpr Number lowest() noexcept
Definition Number.h:336
static constexpr Number min() noexcept
Definition Number.h:324
Number & operator-=(Number const &x)
Definition Number.h:286
constexpr Number operator-() const noexcept
Definition Number.h:248
friend std::ostream & operator<<(std::ostream &os, Number const &x)
Definition Number.h:190
friend constexpr bool operator>(Number const &x, Number const &y) noexcept
Definition Number.h:172
constexpr Number()=default
constexpr int signum() const noexcept
Return the sign of the amount.
Definition Number.h:148
rep mantissa_
Definition Number.h:38
friend constexpr bool operator<=(Number const &x, Number const &y) noexcept
Definition Number.h:178
saveNumberRoundMode(Number::rounding_mode mode) noexcept
Definition Number.h:397
saveNumberRoundMode & operator=(saveNumberRoundMode const &)=delete
Number::rounding_mode mode_
Definition Number.h:390
saveNumberRoundMode(saveNumberRoundMode const &)=delete
T lowest(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
Number operator*(Number const &x, Number const &y)
Definition Number.h:308
Number power(Number const &f, unsigned n)
Definition Number.cpp:613
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
Number operator-(Number const &x, Number const &y)
Definition Number.h:300
Number root(Number f, unsigned d)
Definition Number.cpp:636
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:622
Number root2(Number f)
Definition Number.cpp:701
constexpr Number squelch(Number const &x, Number const &limit) noexcept
Definition Number.h:381
Number operator/(Number const &x, Number const &y)
Definition Number.h:316
constexpr Number abs(Number x) noexcept
Definition Number.h:350