CppCommon  1.0.4.1
C++ Common Library
uint128.cpp
Go to the documentation of this file.
1 
9 #include "common/uint128.h"
10 
11 namespace CppCommon {
12 
13 uint128_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 
58 uint128_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 
76 uint128_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 
94 size_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 
121 std::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 
146 std::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 
171 std::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.
Definition: token_bucket.h:15
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:13
uint128_t operator>>(const uint128_t &value1, const uint128_t &value2) noexcept
Definition: uint128.cpp:76
Unsigned 128-bit integer type definition.