CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
uint128.cpp
Go to the documentation of this file.
1
9#include "common/uint128.h"
10
11namespace CppCommon {
12
13uint128_t operator*(const uint128_t& value1, const uint128_t& value2) noexcept
14{
15 // Split values into four 32-bit parts
16 uint64_t top[4] = { value1._upper >> 32, value1._upper & 0xFFFFFFFF, value1._lower >> 32, value1._lower & 0xFFFFFFFF };
17 uint64_t bottom[4] = { value2._upper >> 32, value2._upper & 0xFFFFFFFF, value2._lower >> 32, value2._lower & 0xFFFFFFFF };
18 uint64_t products[4][4];
19
20 // Multiply each component of the values
21 for (int y = 3; y > -1; --y)
22 for (int x = 3; x > -1; --x)
23 products[3 - x][y] = top[x] * bottom[y];
24
25 // First row
26 uint64_t fourth32 = (products[0][3] & 0xFFFFFFFF);
27 uint64_t third32 = (products[0][2] & 0xFFFFFFFF) + (products[0][3] >> 32);
28 uint64_t second32 = (products[0][1] & 0xFFFFFFFF) + (products[0][2] >> 32);
29 uint64_t first32 = (products[0][0] & 0xFFFFFFFF) + (products[0][1] >> 32);
30
31 // Second row
32 third32 += (products[1][3] & 0xFFFFFFFF);
33 second32 += (products[1][2] & 0xFFFFFFFF) + (products[1][3] >> 32);
34 first32 += (products[1][1] & 0xFFFFFFFF) + (products[1][2] >> 32);
35
36 // Third row
37 second32 += (products[2][3] & 0xFFFFFFFF);
38 first32 += (products[2][2] & 0xFFFFFFFF) + (products[2][3] >> 32);
39
40 // Fourth row
41 first32 += (products[3][3] & 0xFFFFFFFF);
42
43 // Move carry to the next digit
44 third32 += fourth32 >> 32;
45 second32 += third32 >> 32;
46 first32 += second32 >> 32;
47
48 // Remove carry from the current digit
49 fourth32 &= 0xFFFFFFFF;
50 third32 &= 0xFFFFFFFF;
51 second32 &= 0xFFFFFFFF;
52 first32 &= 0xFFFFFFFF;
53
54 // Combine components
55 return uint128_t((first32 << 32) | second32, (third32 << 32) | fourth32);
56}
57
58uint128_t operator<<(const uint128_t& value1, const uint128_t& value2) noexcept
59{
60 const uint64_t shift = value2._lower;
61
62 if (((bool)value2._upper) || (shift >= 128))
63 return 0;
64 else if (shift == 64)
65 return uint128_t(value1._lower, 0);
66 else if (shift == 0)
67 return value1;
68 else if (shift < 64)
69 return uint128_t((value1._upper << shift) + (value1._lower >> (64 - shift)), value1._lower << shift);
70 else if ((128 > shift) && (shift > 64))
71 return uint128_t(value1._lower << (shift - 64), 0);
72 else
73 return 0;
74}
75
76uint128_t operator>>(const uint128_t& value1, const uint128_t& value2) noexcept
77{
78 const uint64_t shift = value2._lower;
79
80 if (((bool)value2._upper) || (shift >= 128))
81 return 0;
82 else if (shift == 64)
83 return uint128_t(0, value1._upper);
84 else if (shift == 0)
85 return value1;
86 else if (shift < 64)
87 return uint128_t(value1._upper >> shift, (value1._upper << (64 - shift)) + (value1._lower >> shift));
88 else if ((128 > shift) && (shift > 64))
89 return uint128_t(0, (value1._upper >> (shift - 64)));
90 else
91 return 0;
92}
93
94size_t uint128_t::bits() const noexcept
95{
96 size_t result = 0;
97
98 if (_upper)
99 {
100 result = 64;
101 uint64_t upper = _upper;
102 while (upper)
103 {
104 upper >>= 1;
105 ++result;
106 }
107 }
108 else
109 {
110 uint64_t lower = _lower;
111 while (lower)
112 {
113 lower >>= 1;
114 ++result;
115 }
116 }
117
118 return result;
119}
120
121std::string uint128_t::string(size_t base, size_t length) const
122{
123 if ((base < 2) || (base > 16))
124 throw std::invalid_argument("Base must be in the range [2, 16]");
125
126 std::string out;
127
128 if (!(*this))
129 out = "0";
130 else
131 {
132 std::pair<uint128_t, uint128_t> qr(*this, 0);
133 do
134 {
135 qr = uint128_t::divmod(qr.first, uint128_t(base));
136 out = "0123456789abcdef"[(uint8_t)qr.second] + out;
137 } while (qr.first != 0);
138 }
139
140 if (out.size() < length)
141 out = std::string(length - out.size(), '0') + out;
142
143 return out;
144}
145
146std::wstring uint128_t::wstring(size_t base, size_t length) const
147{
148 if ((base < 2) || (base > 16))
149 throw std::invalid_argument("Base must be in the range [2, 16]");
150
151 std::wstring out;
152
153 if (!(*this))
154 out = L"0";
155 else
156 {
157 std::pair<uint128_t, uint128_t> qr(*this, 0);
158 do
159 {
160 qr = uint128_t::divmod(qr.first, uint128_t(base));
161 out = L"0123456789abcdef"[(uint8_t)qr.second] + out;
162 } while (qr.first != 0);
163 }
164
165 if (out.size() < length)
166 out = std::wstring(length - out.size(), L'0') + out;
167
168 return out;
169}
170
171std::pair<uint128_t, uint128_t> uint128_t::divmod(const uint128_t& x, const uint128_t& y)
172{
173 if (y == 0)
174 throw std::domain_error("Division by 0");
175 else if (y == 1)
176 return std::pair<uint128_t, uint128_t>(x, 0);
177 else if (x == y)
178 return std::pair<uint128_t, uint128_t>(1, 0);
179 else if ((x == 0) || (x < y))
180 return std::pair<uint128_t, uint128_t>(0, x);
181
182 std::pair<uint128_t, uint128_t> result(0, 0);
183
184 for (size_t i = x.bits(); i > 0; --i)
185 {
186 result.first <<= 1;
187 result.second <<= 1;
188
189 if ((x >> (i - 1u)) & 1)
190 ++result.second;
191
192 if (result.second >= y)
193 {
194 result.second -= y;
195 ++result.first;
196 }
197 }
198
199 return result;
200}
201
202} // namespace CppCommon
Unsigned 128-bit integer type.
Definition uint128.h:28
static std::pair< uint128_t, uint128_t > divmod(const uint128_t &x, const uint128_t &y)
Calculate quotient and remainder when dividing X by Y.
Definition uint128.cpp:171
size_t bits() const noexcept
Get the count of bits.
Definition uint128.cpp:94
std::wstring wstring(size_t base=10, size_t length=0) const
Get wide string from the current 128-bit integer.
Definition uint128.cpp:146
uint64_t lower() const noexcept
Get the lower part of the 128-bit integer.
Definition uint128.h:260
uint64_t upper() const noexcept
Get the upper part of the 128-bit integer.
Definition uint128.h:258
std::string string(size_t base=10, size_t length=0) const
Get string from the current 128-bit integer.
Definition uint128.cpp:121
C++ Common project definitions.
uint128_t operator*(const uint128_t &value1, const uint128_t &value2) noexcept
Definition uint128.cpp:13
std::ostream & operator<<(std::ostream &os, const uint128_t &value)
Definition uint128.inl:155
uint128_t operator>>(const uint128_t &value1, const uint128_t &value2) noexcept
Definition uint128.cpp:76
Unsigned 128-bit integer type definition.