rippled
Loading...
Searching...
No Matches
IOUAmount_test.cpp
1#include <xrpl/beast/unit_test.h>
2#include <xrpl/protocol/IOUAmount.h>
3
4namespace xrpl {
5
7{
8public:
9 void
11 {
12 testcase("zero");
13
14 IOUAmount const z(0, 0);
15
16 BEAST_EXPECT(z.mantissa() == 0);
17 BEAST_EXPECT(z.exponent() == -100);
18 BEAST_EXPECT(!z);
19 BEAST_EXPECT(z.signum() == 0);
20 BEAST_EXPECT(z == beast::zero);
21
22 BEAST_EXPECT((z + z) == z);
23 BEAST_EXPECT((z - z) == z);
24 BEAST_EXPECT(z == -z);
25
26 IOUAmount const zz(beast::zero);
27 BEAST_EXPECT(z == zz);
28
29 // https://github.com/XRPLF/rippled/issues/5170
30 IOUAmount const zzz{};
31 BEAST_EXPECT(zzz == beast::zero);
32 // BEAST_EXPECT(zzz == zz);
33 }
34
35 void
37 {
38 testcase("signum");
39
40 IOUAmount const neg(-1, 0);
41 BEAST_EXPECT(neg.signum() < 0);
42
43 IOUAmount const zer(0, 0);
44 BEAST_EXPECT(zer.signum() == 0);
45
46 IOUAmount const pos(1, 0);
47 BEAST_EXPECT(pos.signum() > 0);
48 }
49
50 void
52 {
53 testcase("beast::Zero Comparisons");
54
55 using beast::zero;
56
57 {
58 IOUAmount const z(zero);
59 BEAST_EXPECT(z == zero);
60 BEAST_EXPECT(z >= zero);
61 BEAST_EXPECT(z <= zero);
62 unexpected(z != zero);
63 unexpected(z > zero);
64 unexpected(z < zero);
65 }
66
67 {
68 IOUAmount const neg(-2, 0);
69 BEAST_EXPECT(neg < zero);
70 BEAST_EXPECT(neg <= zero);
71 BEAST_EXPECT(neg != zero);
72 unexpected(neg == zero);
73 }
74
75 {
76 IOUAmount const pos(2, 0);
77 BEAST_EXPECT(pos > zero);
78 BEAST_EXPECT(pos >= zero);
79 BEAST_EXPECT(pos != zero);
80 unexpected(pos == zero);
81 }
82 }
83
84 void
86 {
87 testcase("IOU Comparisons");
88
89 IOUAmount const n(-2, 0);
90 IOUAmount const z(0, 0);
91 IOUAmount const p(2, 0);
92
93 BEAST_EXPECT(z == z);
94 BEAST_EXPECT(z >= z);
95 BEAST_EXPECT(z <= z);
96 BEAST_EXPECT(z == -z);
97 // NOLINTBEGIN(misc-redundant-expression)
98 unexpected(z > z);
99 unexpected(z < z);
100 unexpected(z != z);
101 // NOLINTEND(misc-redundant-expression)
102 unexpected(z != -z);
103
104 BEAST_EXPECT(n < z);
105 BEAST_EXPECT(n <= z);
106 BEAST_EXPECT(n != z);
107 unexpected(n > z);
108 unexpected(n >= z);
109 unexpected(n == z);
110
111 BEAST_EXPECT(p > z);
112 BEAST_EXPECT(p >= z);
113 BEAST_EXPECT(p != z);
114 unexpected(p < z);
115 unexpected(p <= z);
116 unexpected(p == z);
117
118 BEAST_EXPECT(n < p);
119 BEAST_EXPECT(n <= p);
120 BEAST_EXPECT(n != p);
121 unexpected(n > p);
122 unexpected(n >= p);
123 unexpected(n == p);
124
125 BEAST_EXPECT(p > n);
126 BEAST_EXPECT(p >= n);
127 BEAST_EXPECT(p != n);
128 unexpected(p < n);
129 unexpected(p <= n);
130 unexpected(p == n);
131
132 BEAST_EXPECT(p > -p);
133 BEAST_EXPECT(p >= -p);
134 BEAST_EXPECT(p != -p);
135
136 BEAST_EXPECT(n < -n);
137 BEAST_EXPECT(n <= -n);
138 BEAST_EXPECT(n != -n);
139 }
140
141 void
143 {
144 testcase("IOU strings");
145
146 auto test = [this](IOUAmount const& n, std::string const& expected) {
147 auto const result = to_string(n);
149 ss << "to_string(" << result << "). Expected: " << expected;
150 BEAST_EXPECTS(result == expected, ss.str());
151 };
152
153 for (auto const mantissaSize : {MantissaRange::small, MantissaRange::large})
154 {
155 NumberMantissaScaleGuard const mg(mantissaSize);
156
157 test(IOUAmount(-2, 0), "-2");
158 test(IOUAmount(0, 0), "0");
159 test(IOUAmount(2, 0), "2");
160 test(IOUAmount(25, -3), "0.025");
161 test(IOUAmount(-25, -3), "-0.025");
162 test(IOUAmount(25, 1), "250");
163 test(IOUAmount(-25, 1), "-250");
164 test(IOUAmount(2, 20), "2e20");
165 test(IOUAmount(-2, -20), "-2e-20");
166 }
167 }
168
169 void
171 {
172 testcase("mulRatio");
173
174 /* The range for the mantissa when normalized */
175 constexpr std::int64_t minMantissa = 1000000000000000ull;
176 constexpr std::int64_t maxMantissa = 9999999999999999ull;
177 // log(2,maxMantissa) ~ 53.15
178 /* The range for the exponent when normalized */
179 constexpr int minExponent = -96;
180 constexpr int maxExponent = 80;
181 constexpr auto maxUInt = std::numeric_limits<std::uint32_t>::max();
182
183 {
184 // multiply by a number that would overflow the mantissa, then
185 // divide by the same number, and check we didn't lose any value
186 IOUAmount const bigMan(maxMantissa, 0);
187 BEAST_EXPECT(bigMan == mulRatio(bigMan, maxUInt, maxUInt, true));
188 // rounding mode shouldn't matter as the result is exact
189 BEAST_EXPECT(bigMan == mulRatio(bigMan, maxUInt, maxUInt, false));
190 }
191 {
192 // Similar test as above, but for negative values
193 IOUAmount const bigMan(-maxMantissa, 0);
194 BEAST_EXPECT(bigMan == mulRatio(bigMan, maxUInt, maxUInt, true));
195 // rounding mode shouldn't matter as the result is exact
196 BEAST_EXPECT(bigMan == mulRatio(bigMan, maxUInt, maxUInt, false));
197 }
198
199 {
200 // small amounts
201 IOUAmount const tiny(minMantissa, minExponent);
202 // Round up should give the smallest allowable number
203 BEAST_EXPECT(tiny == mulRatio(tiny, 1, maxUInt, true));
204 BEAST_EXPECT(tiny == mulRatio(tiny, maxUInt - 1, maxUInt, true));
205 // rounding down should be zero
206 BEAST_EXPECT(beast::zero == mulRatio(tiny, 1, maxUInt, false));
207 BEAST_EXPECT(beast::zero == mulRatio(tiny, maxUInt - 1, maxUInt, false));
208
209 // tiny negative numbers
210 IOUAmount const tinyNeg(-minMantissa, minExponent);
211 // Round up should give zero
212 BEAST_EXPECT(beast::zero == mulRatio(tinyNeg, 1, maxUInt, true));
213 BEAST_EXPECT(beast::zero == mulRatio(tinyNeg, maxUInt - 1, maxUInt, true));
214 // rounding down should be tiny
215 BEAST_EXPECT(tinyNeg == mulRatio(tinyNeg, 1, maxUInt, false));
216 BEAST_EXPECT(tinyNeg == mulRatio(tinyNeg, maxUInt - 1, maxUInt, false));
217 }
218
219 { // rounding
220 {
221 IOUAmount const one(1, 0);
222 auto const rup = mulRatio(one, maxUInt - 1, maxUInt, true);
223 auto const rdown = mulRatio(one, maxUInt - 1, maxUInt, false);
224 BEAST_EXPECT(rup.mantissa() - rdown.mantissa() == 1);
225 }
226 {
228 auto const rup = mulRatio(big, maxUInt - 1, maxUInt, true);
229 auto const rdown = mulRatio(big, maxUInt - 1, maxUInt, false);
230 BEAST_EXPECT(rup.mantissa() - rdown.mantissa() == 1);
231 }
232
233 {
234 IOUAmount const negOne(-1, 0);
235 auto const rup = mulRatio(negOne, maxUInt - 1, maxUInt, true);
236 auto const rdown = mulRatio(negOne, maxUInt - 1, maxUInt, false);
237 BEAST_EXPECT(rup.mantissa() - rdown.mantissa() == 1);
238 }
239 }
240
241 {
242 // division by zero
243 IOUAmount one(1, 0);
244 except([&] { mulRatio(one, 1, 0, true); });
245 }
246
247 {
248 // overflow
250 except([&] { mulRatio(big, 2, 0, true); });
251 }
252 } // namespace xrpl
253
254 //--------------------------------------------------------------------------
255
256 void
257 run() override
258 {
259 testZero();
260 testSigNum();
263 testToString();
264 testMulRatio();
265 }
266};
267
268BEAST_DEFINE_TESTSUITE(IOUAmount, basics, xrpl);
269
270} // namespace xrpl
A testsuite class.
Definition suite.h:51
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition suite.h:485
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
bool except(F &&f, String const &reason)
Definition suite.h:434
void run() override
Runs the suite.
Floating point representation of amounts with high dynamic range.
Definition IOUAmount.h:25
mantissa_type mantissa() const noexcept
Definition IOUAmount.h:164
exponent_type exponent() const noexcept
Definition IOUAmount.h:158
int signum() const noexcept
Return the sign of the amount.
Definition IOUAmount.h:152
Sets the new scale and restores the old scale when it leaves scope.
Definition Number.h:814
T max(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
static std::int64_t constexpr minMantissa
Definition IOUAmount.cpp:48
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
static std::int64_t constexpr maxMantissa
Definition IOUAmount.cpp:49
static int constexpr maxExponent
Definition IOUAmount.cpp:52
static int constexpr minExponent
Definition IOUAmount.cpp:51
T str(T... args)