biginteger.h Source File

biginteger.h Source File#

Composable Kernel: biginteger.h Source File
biginteger.h
Go to the documentation of this file.
1// Tencent is pleased to support the open source community by making RapidJSON available.
2//
3// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4//
5// Licensed under the MIT License (the "License"); you may not use this file except
6// in compliance with the License. You may obtain a copy of the License at
7//
8// http://opensource.org/licenses/MIT
9//
10// Unless required by applicable law or agreed to in writing, software distributed
11// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13// specific language governing permissions and limitations under the License.
14
15#ifndef RAPIDJSON_BIGINTEGER_H_
16#define RAPIDJSON_BIGINTEGER_H_
17
18#include "../rapidjson.h"
19
20#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64)
21#include <intrin.h> // for _umul128
22#if !defined(_ARM64EC_)
23#pragma intrinsic(_umul128)
24#else
25#pragma comment(lib, "softintrin")
26#endif
27#endif
28
30namespace internal {
31
33{
34 public:
35 typedef uint64_t Type;
36
37 BigInteger(const BigInteger& rhs) : count_(rhs.count_)
38 {
39 std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
40 }
41
42 explicit BigInteger(uint64_t u) : count_(1) { digits_[0] = u; }
43
44 template <typename Ch>
45 BigInteger(const Ch* decimals, size_t length) : count_(1)
46 {
47 RAPIDJSON_ASSERT(length > 0);
48 digits_[0] = 0;
49 size_t i = 0;
50 const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
51 while(length >= kMaxDigitPerIteration)
52 {
53 AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
54 length -= kMaxDigitPerIteration;
55 i += kMaxDigitPerIteration;
56 }
57
58 if(length > 0)
59 AppendDecimal64(decimals + i, decimals + i + length);
60 }
61
63 {
64 if(this != &rhs)
65 {
66 count_ = rhs.count_;
67 std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
68 }
69 return *this;
70 }
71
73 {
74 digits_[0] = u;
75 count_ = 1;
76 return *this;
77 }
78
80 {
81 Type backup = digits_[0];
82 digits_[0] += u;
83 for(size_t i = 0; i < count_ - 1; i++)
84 {
85 if(digits_[i] >= backup)
86 return *this; // no carry
87 backup = digits_[i + 1];
88 digits_[i + 1] += 1;
89 }
90
91 // Last carry
92 if(digits_[count_ - 1] < backup)
93 PushBack(1);
94
95 return *this;
96 }
97
99 {
100 if(u == 0)
101 return *this = 0;
102 if(u == 1)
103 return *this;
104 if(*this == 1)
105 return *this = u;
106
107 uint64_t k = 0;
108 for(size_t i = 0; i < count_; i++)
109 {
110 uint64_t hi;
111 digits_[i] = MulAdd64(digits_[i], u, k, &hi);
112 k = hi;
113 }
114
115 if(k > 0)
116 PushBack(k);
117
118 return *this;
119 }
120
122 {
123 if(u == 0)
124 return *this = 0;
125 if(u == 1)
126 return *this;
127 if(*this == 1)
128 return *this = u;
129
130 uint64_t k = 0;
131 for(size_t i = 0; i < count_; i++)
132 {
133 const uint64_t c = digits_[i] >> 32;
134 const uint64_t d = digits_[i] & 0xFFFFFFFF;
135 const uint64_t uc = u * c;
136 const uint64_t ud = u * d;
137 const uint64_t p0 = ud + k;
138 const uint64_t p1 = uc + (p0 >> 32);
139 digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
140 k = p1 >> 32;
141 }
142
143 if(k > 0)
144 PushBack(k);
145
146 return *this;
147 }
148
149 BigInteger& operator<<=(size_t shift)
150 {
151 if(IsZero() || shift == 0)
152 return *this;
153
154 size_t offset = shift / kTypeBit;
155 size_t interShift = shift % kTypeBit;
156 RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
157
158 if(interShift == 0)
159 {
160 std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));
161 count_ += offset;
162 }
163 else
164 {
165 digits_[count_] = 0;
166 for(size_t i = count_; i > 0; i--)
167 digits_[i + offset] =
168 (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
169 digits_[offset] = digits_[0] << interShift;
170 count_ += offset;
171 if(digits_[count_])
172 count_++;
173 }
174
175 std::memset(digits_, 0, offset * sizeof(Type));
176
177 return *this;
178 }
179
180 bool operator==(const BigInteger& rhs) const
181 {
182 return count_ == rhs.count_ &&
183 std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
184 }
185
186 bool operator==(const Type rhs) const { return count_ == 1 && digits_[0] == rhs; }
187
189 {
190 static const uint32_t kPow5[12] = {5,
191 5 * 5,
192 5 * 5 * 5,
193 5 * 5 * 5 * 5,
194 5 * 5 * 5 * 5 * 5,
195 5 * 5 * 5 * 5 * 5 * 5,
196 5 * 5 * 5 * 5 * 5 * 5 * 5,
197 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
198 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
199 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
200 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
201 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5};
202 if(exp == 0)
203 return *this;
204 for(; exp >= 27; exp -= 27)
205 *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
206 for(; exp >= 13; exp -= 13)
207 *this *= static_cast<uint32_t>(1220703125u); // 5^13
208 if(exp > 0)
209 *this *= kPow5[exp - 1];
210 return *this;
211 }
212
213 // Compute absolute difference of this and rhs.
214 // Assume this != rhs
215 bool Difference(const BigInteger& rhs, BigInteger* out) const
216 {
217 int cmp = Compare(rhs);
218 RAPIDJSON_ASSERT(cmp != 0);
219 const BigInteger *a, *b; // Makes a > b
220 bool ret;
221 if(cmp < 0)
222 {
223 a = &rhs;
224 b = this;
225 ret = true;
226 }
227 else
228 {
229 a = this;
230 b = &rhs;
231 ret = false;
232 }
233
234 Type borrow = 0;
235 for(size_t i = 0; i < a->count_; i++)
236 {
237 Type d = a->digits_[i] - borrow;
238 if(i < b->count_)
239 d -= b->digits_[i];
240 borrow = (d > a->digits_[i]) ? 1 : 0;
241 out->digits_[i] = d;
242 if(d != 0)
243 out->count_ = i + 1;
244 }
245
246 return ret;
247 }
248
249 int Compare(const BigInteger& rhs) const
250 {
251 if(count_ != rhs.count_)
252 return count_ < rhs.count_ ? -1 : 1;
253
254 for(size_t i = count_; i-- > 0;)
255 if(digits_[i] != rhs.digits_[i])
256 return digits_[i] < rhs.digits_[i] ? -1 : 1;
257
258 return 0;
259 }
260
261 size_t GetCount() const { return count_; }
262 Type GetDigit(size_t index) const
263 {
264 RAPIDJSON_ASSERT(index < count_);
265 return digits_[index];
266 }
267 bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
268
269 private:
270 template <typename Ch>
271 void AppendDecimal64(const Ch* begin, const Ch* end)
272 {
273 uint64_t u = ParseUint64(begin, end);
274 if(IsZero())
275 *this = u;
276 else
277 {
278 unsigned exp = static_cast<unsigned>(end - begin);
279 (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
280 }
281 }
282
283 void PushBack(Type digit)
284 {
285 RAPIDJSON_ASSERT(count_ < kCapacity);
286 digits_[count_++] = digit;
287 }
288
289 template <typename Ch>
290 static uint64_t ParseUint64(const Ch* begin, const Ch* end)
291 {
292 uint64_t r = 0;
293 for(const Ch* p = begin; p != end; ++p)
294 {
295 RAPIDJSON_ASSERT(*p >= Ch('0') && *p <= Ch('9'));
296 r = r * 10u + static_cast<unsigned>(*p - Ch('0'));
297 }
298 return r;
299 }
300
301 // Assume a * b + k < 2^128
302 static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh)
303 {
304#if defined(_MSC_VER) && defined(_M_AMD64)
305 uint64_t low = _umul128(a, b, outHigh) + k;
306 if(low < k)
307 (*outHigh)++;
308 return low;
309#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && \
310 defined(__x86_64__)
311 __extension__ typedef unsigned __int128 uint128;
312 uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
313 p += k;
314 *outHigh = static_cast<uint64_t>(p >> 64);
315 return static_cast<uint64_t>(p);
316#else
317 const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
318 uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
319 x1 += (x0 >> 32); // can't give carry
320 x1 += x2;
321 if(x1 < x2)
322 x3 += (static_cast<uint64_t>(1) << 32);
323 uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
324 uint64_t hi = x3 + (x1 >> 32);
325
326 lo += k;
327 if(lo < k)
328 hi++;
329 *outHigh = hi;
330 return lo;
331#endif
332 }
333
334 static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
335 static const size_t kCapacity = kBitCount / sizeof(Type);
336 static const size_t kTypeBit = sizeof(Type) * 8;
337
338 Type digits_[kCapacity];
339 size_t count_;
340};
341
342} // namespace internal
344
345#endif // RAPIDJSON_BIGINTEGER_H_
BigInteger & operator<<=(size_t shift)
Definition biginteger.h:149
BigInteger & operator=(uint64_t u)
Definition biginteger.h:72
uint64_t Type
Definition biginteger.h:35
BigInteger & operator*=(uint64_t u)
Definition biginteger.h:98
BigInteger(const Ch *decimals, size_t length)
Definition biginteger.h:45
bool operator==(const BigInteger &rhs) const
Definition biginteger.h:180
Type GetDigit(size_t index) const
Definition biginteger.h:262
bool operator==(const Type rhs) const
Definition biginteger.h:186
size_t GetCount() const
Definition biginteger.h:261
BigInteger(const BigInteger &rhs)
Definition biginteger.h:37
BigInteger & operator=(const BigInteger &rhs)
Definition biginteger.h:62
BigInteger(uint64_t u)
Definition biginteger.h:42
BigInteger & operator*=(uint32_t u)
Definition biginteger.h:121
BigInteger & operator+=(uint64_t u)
Definition biginteger.h:79
bool Difference(const BigInteger &rhs, BigInteger *out) const
Definition biginteger.h:215
bool IsZero() const
Definition biginteger.h:267
BigInteger & MultiplyPow5(unsigned exp)
Definition biginteger.h:188
int Compare(const BigInteger &rhs) const
Definition biginteger.h:249
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition rapidjson.h:451
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition rapidjson.h:121
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition rapidjson.h:124
Definition allocators.h:459
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1517
common definitions and configuration
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
Definition rapidjson.h:326
unsigned int uint32_t
Definition stdint.h:126
unsigned __int64 uint64_t
Definition stdint.h:136