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 friend constexpr bool
154 operator>(Number const& x, Number const& y) noexcept
155 {
156 return y < x;
157 }
158
159 friend constexpr bool
160 operator<=(Number const& x, Number const& y) noexcept
161 {
162 return !(y < x);
163 }
164
165 friend constexpr bool
166 operator>=(Number const& x, Number const& y) noexcept
167 {
168 return !(x < y);
169 }
170
172 operator<<(std::ostream& os, Number const& x)
173 {
174 return os << to_string(x);
175 }
176
177 // Thread local rounding control. Default is to_nearest
179 static rounding_mode
180 getround();
181 // Returns previously set mode
182 static rounding_mode
184
185private:
186 static thread_local rounding_mode mode_;
187
188 void
189 normalize();
190 constexpr bool
191 isnormal() const noexcept;
192
193 class Guard;
194};
195
196inline constexpr Number::Number(rep mantissa, int exponent, unchecked) noexcept
198{
199}
200
203{
204 normalize();
205}
206
207inline Number::Number(rep mantissa) : Number{mantissa, 0}
208{
209}
210
211inline constexpr Number::rep
212Number::mantissa() const noexcept
213{
214 return mantissa_;
215}
216
217inline constexpr int
218Number::exponent() const noexcept
219{
220 return exponent_;
221}
222
223inline constexpr Number
224Number::operator+() const noexcept
225{
226 return *this;
227}
228
229inline constexpr Number
230Number::operator-() const noexcept
231{
232 auto x = *this;
233 x.mantissa_ = -x.mantissa_;
234 return x;
235}
236
237inline Number&
239{
240 *this += Number{1000000000000000, -15, unchecked{}};
241 return *this;
242}
243
244inline Number
246{
247 auto x = *this;
248 ++(*this);
249 return x;
250}
251
252inline Number&
254{
255 *this -= Number{1000000000000000, -15, unchecked{}};
256 return *this;
257}
258
259inline Number
261{
262 auto x = *this;
263 --(*this);
264 return x;
265}
266
267inline Number&
269{
270 return *this += -x;
271}
272
273inline Number
274operator+(Number const& x, Number const& y)
275{
276 auto z = x;
277 z += y;
278 return z;
279}
280
281inline Number
282operator-(Number const& x, Number const& y)
283{
284 auto z = x;
285 z -= y;
286 return z;
287}
288
289inline Number
290operator*(Number const& x, Number const& y)
291{
292 auto z = x;
293 z *= y;
294 return z;
295}
296
297inline Number
298operator/(Number const& x, Number const& y)
299{
300 auto z = x;
301 z /= y;
302 return z;
303}
304
305inline constexpr Number
306Number::min() noexcept
307{
309}
310
311inline constexpr Number
312Number::max() noexcept
313{
315}
316
317inline constexpr Number
319{
321}
322
323inline constexpr bool
324Number::isnormal() const noexcept
325{
326 auto const abs_m = mantissa_ < 0 ? -mantissa_ : mantissa_;
327 return minMantissa <= abs_m && abs_m <= maxMantissa &&
329}
330
331inline constexpr Number
332abs(Number x) noexcept
333{
334 if (x < Number{})
335 x = -x;
336 return x;
337}
338
339// Returns f^n
340// Uses a log_2(n) number of multiplications
341
342Number
343power(Number const& f, unsigned n);
344
345// Returns f^(1/d)
346// Uses Newton–Raphson iterations until the result stops changing
347// to find the root of the polynomial g(x) = x^d - f
348
349Number
350root(Number f, unsigned d);
351
352Number
353root2(Number f);
354
355// Returns f^(n/d)
356
357Number
358power(Number const& f, unsigned n, unsigned d);
359
360// Return 0 if abs(x) < limit, else returns x
361
362inline constexpr Number
363squelch(Number const& x, Number const& limit) noexcept
364{
365 if (abs(x) < limit)
366 return Number{};
367 return x;
368}
369
371{
373
374public:
376 {
378 }
380 : mode_{mode}
381 {
382 }
386};
387
388// saveNumberRoundMode doesn't do quite enough for us. What we want is a
389// Number::RoundModeGuard that sets the new mode and restores the old mode
390// when it leaves scope. Since Number doesn't have that facility, we'll
391// build it here.
393{
395
396public:
398 : saved_{Number::setround(mode)}
399 {
400 }
401
403
406};
407
408} // namespace ripple
409
410#endif // RIPPLE_BASICS_NUMBER_H_INCLUDED
NumberRoundModeGuard(NumberRoundModeGuard const &)=delete
NumberRoundModeGuard & operator=(NumberRoundModeGuard const &)=delete
saveNumberRoundMode saved_
Definition: Number.h:394
NumberRoundModeGuard(Number::rounding_mode mode) noexcept
Definition: Number.h:397
constexpr bool isnormal() const noexcept
Definition: Number.h:324
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:253
static constexpr int maxExponent
Definition: Number.h:48
static constexpr std::int64_t minMantissa
Definition: Number.h:43
constexpr int exponent() const noexcept
Definition: Number.h:218
static thread_local rounding_mode mode_
Definition: Number.h:186
constexpr Number operator+() const noexcept
Definition: Number.h:224
void normalize()
Definition: Number.cpp:178
static constexpr Number max() noexcept
Definition: Number.h:312
int exponent_
Definition: Number.h:39
static rounding_mode getround()
Definition: Number.cpp:47
Number & operator++()
Definition: Number.h:238
static constexpr int minExponent
Definition: Number.h:47
friend constexpr bool operator!=(Number const &x, Number const &y) noexcept
Definition: Number.h:111
friend constexpr bool operator>=(Number const &x, Number const &y) noexcept
Definition: Number.h:166
static rounding_mode setround(rounding_mode mode)
Definition: Number.cpp:53
constexpr rep mantissa() const noexcept
Definition: Number.h:212
static constexpr Number lowest() noexcept
Definition: Number.h:318
static constexpr Number min() noexcept
Definition: Number.h:306
Number & operator-=(Number const &x)
Definition: Number.h:268
constexpr Number operator-() const noexcept
Definition: Number.h:230
friend std::ostream & operator<<(std::ostream &os, Number const &x)
Definition: Number.h:172
friend constexpr bool operator>(Number const &x, Number const &y) noexcept
Definition: Number.h:154
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:160
saveNumberRoundMode(Number::rounding_mode mode) noexcept
Definition: Number.h:379
saveNumberRoundMode & operator=(saveNumberRoundMode const &)=delete
Number::rounding_mode mode_
Definition: Number.h:372
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:290
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:282
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:363
Number operator/(Number const &x, Number const &y)
Definition: Number.h:298
constexpr Number abs(Number x) noexcept
Definition: Number.h:332