xrpld
Loading...
Searching...
No Matches
tests/libxrpl/basics/IOUAmount.cpp
1#include <xrpl/protocol/IOUAmount.h>
2
3#include <xrpl/basics/Number.h>
4#include <xrpl/beast/utility/Zero.h>
5
6#include <gtest/gtest.h>
7
8#include <cstdint>
9#include <limits>
10#include <sstream>
11#include <string>
12
13namespace xrpl {
14
15TEST(IOUAmountTest, zero)
16{
17 IOUAmount const z(0, 0);
18
19 EXPECT_EQ(z.mantissa(), 0);
20 EXPECT_EQ(z.exponent(), -100);
21 EXPECT_FALSE(z);
22 EXPECT_EQ(z.signum(), 0);
23 EXPECT_EQ(z, beast::kZero);
24
25 EXPECT_EQ((z + z), z);
26 EXPECT_EQ((z - z), z);
27 EXPECT_EQ(z, -z);
28
29 IOUAmount const zz(beast::kZero);
30 EXPECT_EQ(z, zz);
31
32 // https://github.com/XRPLF/rippled/issues/5170
33 IOUAmount const zzz{};
34 EXPECT_EQ(zzz, beast::kZero);
35 // EXPECT_EQ(zzz, zz);
36}
37
38TEST(IOUAmountTest, sig_num)
39{
40 IOUAmount const neg(-1, 0);
41 EXPECT_LT(neg.signum(), 0);
42
43 IOUAmount const zer(0, 0);
44 EXPECT_EQ(zer.signum(), 0);
45
46 IOUAmount const pos(1, 0);
47 EXPECT_GT(pos.signum(), 0);
48}
49
50TEST(IOUAmountTest, beast_zero)
51{
52 using beast::kZero;
53
54 {
55 IOUAmount const z(kZero);
56 EXPECT_TRUE(z == kZero);
57 EXPECT_TRUE(z >= kZero);
58 EXPECT_TRUE(z <= kZero);
59 EXPECT_FALSE(z != kZero);
60 EXPECT_FALSE(z > kZero);
61 EXPECT_FALSE(z < kZero);
62 }
63
64 {
65 IOUAmount const neg(-2, 0);
66 EXPECT_TRUE(neg < kZero);
67 EXPECT_TRUE(neg <= kZero);
68 EXPECT_TRUE(neg != kZero);
69 EXPECT_FALSE(neg == kZero);
70 }
71
72 {
73 IOUAmount const pos(2, 0);
74 EXPECT_TRUE(pos > kZero);
75 EXPECT_TRUE(pos >= kZero);
76 EXPECT_TRUE(pos != kZero);
77 EXPECT_FALSE(pos == kZero);
78 }
79}
80
81TEST(IOUAmountTest, comparisons)
82{
83 IOUAmount const n(-2, 0);
84 IOUAmount const z(0, 0);
85 IOUAmount const p(2, 0);
86 // For code readability, we want to use general
87 // EXPECT_TRUE instead of specific EXPECT_EQ etc.
88 EXPECT_TRUE(z == z);
89 EXPECT_TRUE(z >= z);
90 EXPECT_TRUE(z <= z);
91 EXPECT_TRUE(z == -z);
92 // NOLINTBEGIN(misc-redundant-expression)
93 EXPECT_FALSE(z > z);
94 EXPECT_FALSE(z < z);
95 EXPECT_FALSE(z != z);
96 // NOLINTEND(misc-redundant-expression)
97 EXPECT_FALSE(z != -z);
98
99 EXPECT_TRUE(n < z);
100 EXPECT_TRUE(n <= z);
101 EXPECT_TRUE(n != z);
102 EXPECT_FALSE(n > z);
103 EXPECT_FALSE(n >= z);
104 EXPECT_FALSE(n == z);
105
106 EXPECT_TRUE(p > z);
107 EXPECT_TRUE(p >= z);
108 EXPECT_TRUE(p != z);
109 EXPECT_FALSE(p < z);
110 EXPECT_FALSE(p <= z);
111 EXPECT_FALSE(p == z);
112
113 EXPECT_TRUE(n < p);
114 EXPECT_TRUE(n <= p);
115 EXPECT_TRUE(n != p);
116 EXPECT_FALSE(n > p);
117 EXPECT_FALSE(n >= p);
118 EXPECT_FALSE(n == p);
119
120 EXPECT_TRUE(p > n);
121 EXPECT_TRUE(p >= n);
122 EXPECT_TRUE(p != n);
123 EXPECT_FALSE(p < n);
124 EXPECT_FALSE(p <= n);
125 EXPECT_FALSE(p == n);
126
127 EXPECT_TRUE(p > -p);
128 EXPECT_TRUE(p >= -p);
129 EXPECT_TRUE(p != -p);
130
131 EXPECT_TRUE(n < -n);
132 EXPECT_TRUE(n <= -n);
133 EXPECT_TRUE(n != -n);
134}
135
136TEST(IOUAmountTest, to_string)
137{
138 auto test = [](IOUAmount const& n, std::string const& expected) {
139 auto const result = to_string(n);
141 ss << "to_string(" << result << "). Expected: " << expected;
142 EXPECT_EQ(result, expected) << ss.str();
143 };
144
145 for (auto const mantissaSize : MantissaRange::getAllScales())
146 {
147 NumberMantissaScaleGuard const mg(mantissaSize);
148
149 test(IOUAmount(-2, 0), "-2");
150 test(IOUAmount(0, 0), "0");
151 test(IOUAmount(2, 0), "2");
152 test(IOUAmount(25, -3), "0.025");
153 test(IOUAmount(-25, -3), "-0.025");
154 test(IOUAmount(25, 1), "250");
155 test(IOUAmount(-25, 1), "-250");
156 test(IOUAmount(2, 20), "2e20");
157 test(IOUAmount(-2, -20), "-2e-20");
158 }
159}
160
161TEST(IOUAmountTest, mul_ratio)
162{
163 /* The range for the mantissa when normalized */
164 constexpr std::int64_t kMinMantissa = 1000000000000000ull;
165 constexpr std::int64_t kMaxMantissa = 9999999999999999ull;
166 // log(2,maxMantissa) ~ 53.15
167 /* The range for the exponent when normalized */
168 constexpr int kMinExponent = -96;
169 constexpr int kMaxExponent = 80;
170 constexpr auto kMaxUInt = std::numeric_limits<std::uint32_t>::max();
171
172 {
173 // multiply by a number that would overflow the mantissa, then
174 // divide by the same number, and check we didn't lose any value
175 IOUAmount const bigMan(kMaxMantissa, 0);
176 EXPECT_EQ(bigMan, mulRatio(bigMan, kMaxUInt, kMaxUInt, true));
177 // rounding mode shouldn't matter as the result is exact
178 EXPECT_EQ(bigMan, mulRatio(bigMan, kMaxUInt, kMaxUInt, false));
179 }
180 {
181 // Similar test as above, but for negative values
182 IOUAmount const bigMan(-kMaxMantissa, 0);
183 EXPECT_EQ(bigMan, mulRatio(bigMan, kMaxUInt, kMaxUInt, true));
184 // rounding mode shouldn't matter as the result is exact
185 EXPECT_EQ(bigMan, mulRatio(bigMan, kMaxUInt, kMaxUInt, false));
186 }
187
188 {
189 // small amounts
191 // Round up should give the smallest allowable number
192 EXPECT_EQ(tiny, mulRatio(tiny, 1, kMaxUInt, true));
193 EXPECT_EQ(tiny, mulRatio(tiny, kMaxUInt - 1, kMaxUInt, true));
194 // rounding down should be zero
195 EXPECT_EQ(beast::kZero, mulRatio(tiny, 1, kMaxUInt, false));
196 EXPECT_EQ(beast::kZero, mulRatio(tiny, kMaxUInt - 1, kMaxUInt, false));
197
198 // tiny negative numbers
199 IOUAmount const tinyNeg(-kMinMantissa, kMinExponent);
200 // Round up should give zero
201 EXPECT_EQ(beast::kZero, mulRatio(tinyNeg, 1, kMaxUInt, true));
202 EXPECT_EQ(beast::kZero, mulRatio(tinyNeg, kMaxUInt - 1, kMaxUInt, true));
203 // rounding down should be tiny
204 EXPECT_EQ(tinyNeg, mulRatio(tinyNeg, 1, kMaxUInt, false));
205 EXPECT_EQ(tinyNeg, mulRatio(tinyNeg, kMaxUInt - 1, kMaxUInt, false));
206 }
207
208 { // rounding
209 {
210 IOUAmount const one(1, 0);
211 auto const rup = mulRatio(one, kMaxUInt - 1, kMaxUInt, true);
212 auto const rdown = mulRatio(one, kMaxUInt - 1, kMaxUInt, false);
213 EXPECT_EQ(rup.mantissa() - rdown.mantissa(), 1);
214 }
215 {
217 auto const rup = mulRatio(big, kMaxUInt - 1, kMaxUInt, true);
218 auto const rdown = mulRatio(big, kMaxUInt - 1, kMaxUInt, false);
219 EXPECT_EQ(rup.mantissa() - rdown.mantissa(), 1);
220 }
221
222 {
223 IOUAmount const negOne(-1, 0);
224 auto const rup = mulRatio(negOne, kMaxUInt - 1, kMaxUInt, true);
225 auto const rdown = mulRatio(negOne, kMaxUInt - 1, kMaxUInt, false);
226 EXPECT_EQ(rup.mantissa() - rdown.mantissa(), 1);
227 }
228 }
229
230 {
231 // division by zero
232 IOUAmount const one(1, 0);
233 EXPECT_ANY_THROW({ mulRatio(one, 1, 0, true); });
234 }
235
236 {
237 // overflow
239 EXPECT_ANY_THROW({ mulRatio(big, 2, 0, true); });
240 }
241}
242
243} // namespace xrpl
Floating point representation of amounts with high dynamic range.
Definition IOUAmount.h:26
mantissa_type mantissa() const noexcept
Definition IOUAmount.h:172
exponent_type exponent() const noexcept
Definition IOUAmount.h:166
int signum() const noexcept
Return the sign of the amount.
Definition IOUAmount.h:158
Sets the new scale and restores the old scale when it leaves scope.
Definition Number.h:963
T max(T... args)
constexpr Zero kZero
Definition Zero.h:30
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
static constexpr int kMinExponent
static constexpr std::int64_t kMinMantissa
TEST(FileUtilitiesTest, get_file_contents)
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
static constexpr std::int64_t kMaxMantissa
static constexpr int kMaxExponent
T str(T... args)
static std::set< MantissaScale > const & getAllScales()
Definition Number.h:178