Qrack  10.0
General classical-emulating-quantum development framework
big_integer.hpp
Go to the documentation of this file.
1 //
3 // (C) Daniel Strano and the Qimcifa contributors, 2022, 2023. All rights reserved.
4 //
5 // This header has been adapted for OpenCL and C, from big_integer.c by Andre Azevedo.
6 //
7 // Original file:
8 //
9 // big_integer.c
10 // Description: "Arbitrary"-precision integer
11 // Author: Andre Azevedo <http://github.com/andreazevedo>
12 //
13 // The MIT License (MIT)
14 //
15 // Copyright (c) 2014 Andre Azevedo
16 //
17 // Permission is hereby granted, free of charge, to any person obtaining a copy
18 // of this software and associated documentation files (the "Software"), to deal
19 // in the Software without restriction, including without limitation the rights
20 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21 // copies of the Software, and to permit persons to whom the Software is
22 // furnished to do so, subject to the following conditions:
23 //
24 // The above copyright notice and this permission notice shall be included in all
25 // copies or substantial portions of the Software.
26 //
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 // SOFTWARE.
34 
35 #pragma once
36 
37 #include "config.h"
38 
39 #include <cmath>
40 #include <cstddef>
41 #include <cstdint>
42 
43 using std::size_t;
44 
45 #ifdef __SIZEOF_INT128__
46 #define BIG_INTEGER_WORD_BITS 128U
47 #define BIG_INTEGER_WORD_POWER 7U
48 #define BIG_INTEGER_WORD unsigned __int128
49 #define BIG_INTEGER_HALF_WORD uint64_t
50 #define BIG_INTEGER_HALF_WORD_MASK 0xFFFFFFFFFFFFFFFFULL
51 #define BIG_INTEGER_HALF_WORD_MASK_NOT 0xFFFFFFFFFFFFFFFF0000000000000000ULL
52 #else
53 #define BIG_INTEGER_WORD_BITS 64U
54 #define BIG_INTEGER_WORD_POWER 6U
55 #define BIG_INTEGER_WORD uint64_t
56 #define BIG_INTEGER_HALF_WORD uint32_t
57 #define BIG_INTEGER_HALF_WORD_MASK 0xFFFFFFFFULL
58 #define BIG_INTEGER_HALF_WORD_MASK_NOT 0xFFFFFFFF00000000ULL
59 #endif
60 
61 // This can be any power of 2 greater than (or equal to) 64:
62 constexpr size_t BIG_INTEGER_BITS = (1 << QBCAPPOW);
64 
65 // The rest of the constants need to be consistent with the one above:
69 
70 typedef struct BigInteger {
72 
73  inline BigInteger()
74  {
75  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
76  bits[i] = 0U;
77  }
78  }
79 
80  inline BigInteger(const BigInteger& val)
81  {
82  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
83  bits[i] = val.bits[i];
84  }
85  }
86 
87  inline BigInteger(const BIG_INTEGER_WORD& val)
88  {
89  bits[0] = val;
90  for (int i = 1; i < BIG_INTEGER_WORD_SIZE; ++i) {
91  bits[i] = 0U;
92  }
93  }
94 
95 #ifdef __SIZEOF_INT128__
96  inline explicit operator unsigned __int128() const { return (unsigned __int128)bits[0U]; }
97 #endif
98  inline explicit operator uint64_t() const { return (uint64_t)bits[0U]; }
99  inline explicit operator uint32_t() const { return (uint32_t)bits[0U]; }
101 
102 inline void bi_set_0(BigInteger* p)
103 {
104  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
105  p->bits[i] = 0U;
106  }
107 }
108 
109 inline BigInteger bi_copy(const BigInteger& in)
110 {
111  BigInteger result;
112  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
113  result.bits[i] = in.bits[i];
114  }
115  return result;
116 }
117 
118 inline void bi_copy_ip(const BigInteger& in, BigInteger* out)
119 {
120  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
121  out->bits[i] = in.bits[i];
122  }
123 }
124 
125 inline int bi_compare(const BigInteger& left, const BigInteger& right)
126 {
127  for (int i = BIG_INTEGER_MAX_WORD_INDEX; i >= 0; --i) {
128  if (left.bits[i] > right.bits[i]) {
129  return 1;
130  }
131 
132  if (left.bits[i] < right.bits[i]) {
133  return -1;
134  }
135  }
136 
137  return 0;
138 }
139 
140 inline int bi_compare_0(const BigInteger& left)
141 {
142  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
143  if (left.bits[i]) {
144  return 1;
145  }
146  }
147 
148  return 0;
149 }
150 
151 inline int bi_compare_1(const BigInteger& left)
152 {
153  for (int i = BIG_INTEGER_MAX_WORD_INDEX; i > 0; --i) {
154  if (left.bits[i]) {
155  return 1;
156  }
157  }
158 
159  if (left.bits[0] > 1U) {
160  return 1;
161  }
162 
163  if (left.bits[0] < 1U) {
164  return -1;
165  }
166 
167  return 0;
168 }
169 
170 inline BigInteger operator+(const BigInteger& left, const BigInteger& right)
171 {
172  BigInteger result;
173  result.bits[0U] = 0U;
174  for (int i = 0; i < BIG_INTEGER_MAX_WORD_INDEX; ++i) {
175  result.bits[i] += left.bits[i] + right.bits[i];
176  result.bits[i + 1] = (result.bits[i] < left.bits[i]) ? 1 : 0;
177  }
179  return result;
180 }
181 
182 inline void bi_add_ip(BigInteger* left, const BigInteger& right)
183 {
184  for (int i = 0; i < BIG_INTEGER_MAX_WORD_INDEX; ++i) {
185  BIG_INTEGER_WORD temp = left->bits[i];
186  left->bits[i] += right.bits[i];
187  int j = i;
188  while ((j < BIG_INTEGER_MAX_WORD_INDEX) && (left->bits[j] < temp)) {
189  temp = left->bits[++j]++;
190  }
191  }
193 }
194 
195 inline BigInteger operator-(const BigInteger& left, const BigInteger& right)
196 {
197  BigInteger result;
198  result.bits[0U] = 0U;
199  for (int i = 0; i < BIG_INTEGER_MAX_WORD_INDEX; ++i) {
200  result.bits[i] += left.bits[i] - right.bits[i];
201  result.bits[i + 1] = (result.bits[i] > left.bits[i]) ? -1 : 0;
202  }
204  return result;
205 }
206 
207 inline void bi_sub_ip(BigInteger* left, const BigInteger& right)
208 {
209  for (int i = 0; i < BIG_INTEGER_MAX_WORD_INDEX; ++i) {
210  BIG_INTEGER_WORD temp = left->bits[i];
211  left->bits[i] -= right.bits[i];
212  int j = i;
213  while ((j < BIG_INTEGER_MAX_WORD_INDEX) && (left->bits[j] > temp)) {
214  temp = left->bits[++j]--;
215  }
216  }
218 }
219 
220 inline void bi_increment(BigInteger* pBigInt, const BIG_INTEGER_WORD& value)
221 {
222  BIG_INTEGER_WORD temp = pBigInt->bits[0];
223  pBigInt->bits[0] += value;
224 
225  if (temp <= pBigInt->bits[0]) {
226  return;
227  }
228 
229  for (int i = 1; i < BIG_INTEGER_WORD_SIZE; i++) {
230  temp = pBigInt->bits[i]++;
231  if (temp <= pBigInt->bits[i]) {
232  break;
233  }
234  }
235 }
236 
237 inline void bi_decrement(BigInteger* pBigInt, const BIG_INTEGER_WORD& value)
238 {
239  BIG_INTEGER_WORD temp = pBigInt->bits[0];
240  pBigInt->bits[0] -= value;
241 
242  if (temp >= pBigInt->bits[0]) {
243  return;
244  }
245 
246  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; i++) {
247  temp = pBigInt->bits[i]--;
248  if (temp >= pBigInt->bits[i]) {
249  break;
250  }
251  }
252 }
253 
255 {
256  BigInteger result;
257  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
258  result.bits[i] = a[i];
259  }
260 
261  return result;
262 }
263 
264 inline BigInteger bi_lshift_word(const BigInteger& left, BIG_INTEGER_WORD rightMult)
265 {
266  if (!rightMult) {
267  return left;
268  }
269 
270  BigInteger result = 0;
271  for (int i = rightMult; i < BIG_INTEGER_WORD_SIZE; ++i) {
272  result.bits[i] = left.bits[i - rightMult];
273  }
274 
275  return result;
276 }
277 
278 inline void bi_lshift_word_ip(BigInteger* left, BIG_INTEGER_WORD rightMult)
279 {
280  rightMult &= 63U;
281 
282  if (!rightMult) {
283  return;
284  }
285 
286  for (int i = rightMult; i < BIG_INTEGER_WORD_SIZE; ++i) {
287  left->bits[i] = left->bits[i - rightMult];
288  }
289  for (BIG_INTEGER_WORD i = 0U; i < rightMult; ++i) {
290  left->bits[i] = 0U;
291  }
292 }
293 
294 inline BigInteger bi_rshift_word(const BigInteger& left, const BIG_INTEGER_WORD& rightMult)
295 {
296  if (!rightMult) {
297  return left;
298  }
299 
300  BigInteger result = 0U;
301  for (int i = rightMult; i < BIG_INTEGER_WORD_SIZE; ++i) {
302  result.bits[i - rightMult] = left.bits[i];
303  }
304 
305  return result;
306 }
307 
308 inline void bi_rshift_word_ip(BigInteger* left, const BIG_INTEGER_WORD& rightMult)
309 {
310  if (!rightMult) {
311  return;
312  }
313 
314  for (int i = rightMult; i < BIG_INTEGER_WORD_SIZE; ++i) {
315  left->bits[i - rightMult] = left->bits[i];
316  }
317  for (BIG_INTEGER_WORD i = 0U; i < rightMult; ++i) {
318  left->bits[BIG_INTEGER_MAX_WORD_INDEX - i] = 0U;
319  }
320 }
321 
323 {
324  const int rShift64 = right >> BIG_INTEGER_WORD_POWER;
325  const int rMod = right - (rShift64 << BIG_INTEGER_WORD_POWER);
326 
327  BigInteger result = bi_lshift_word(left, rShift64);
328 
329  if (!rMod) {
330  return result;
331  }
332 
333  const int rModComp = BIG_INTEGER_WORD_BITS - rMod;
334  BIG_INTEGER_WORD carry = 0U;
335  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
336  right = result.bits[i];
337  result.bits[i] = carry | (right << rMod);
338  carry = right >> rModComp;
339  }
340 
341  return result;
342 }
343 
344 inline void bi_lshift_ip(BigInteger* left, BIG_INTEGER_WORD right)
345 {
346  const int rShift64 = right >> BIG_INTEGER_WORD_POWER;
347  const int rMod = right - (rShift64 << BIG_INTEGER_WORD_POWER);
348 
349  bi_lshift_word_ip(left, rShift64);
350 
351  if (!rMod) {
352  return;
353  }
354 
355  const int rModComp = BIG_INTEGER_WORD_BITS - rMod;
356  BIG_INTEGER_WORD carry = 0U;
357  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
358  right = left->bits[i];
359  left->bits[i] = carry | (right << rMod);
360  carry = right >> rModComp;
361  }
362 }
363 
365 {
366  const int rShift64 = right >> BIG_INTEGER_WORD_POWER;
367  const int rMod = right - (rShift64 << BIG_INTEGER_WORD_POWER);
368 
369  BigInteger result = bi_rshift_word(left, rShift64);
370 
371  if (!rMod) {
372  return result;
373  }
374 
375  const int rModComp = BIG_INTEGER_WORD_BITS - rMod;
376  BIG_INTEGER_WORD carry = 0U;
377  for (int i = BIG_INTEGER_MAX_WORD_INDEX; i >= 0; --i) {
378  right = result.bits[i];
379  result.bits[i] = carry | (right >> rMod);
380  carry = right << rModComp;
381  }
382 
383  return result;
384 }
385 
386 inline void bi_rshift_ip(BigInteger* left, BIG_INTEGER_WORD right)
387 {
388  const int rShift64 = right >> BIG_INTEGER_WORD_POWER;
389  const int rMod = right - (rShift64 << BIG_INTEGER_WORD_POWER);
390 
391  bi_rshift_word_ip(left, rShift64);
392 
393  if (!rMod) {
394  return;
395  }
396 
397  const int rModComp = BIG_INTEGER_WORD_BITS - rMod;
398  BIG_INTEGER_WORD carry = 0U;
399  for (int i = BIG_INTEGER_MAX_WORD_INDEX; i >= 0; --i) {
400  right = left->bits[i];
401  left->bits[i] = carry | (right >> rMod);
402  carry = right << rModComp;
403  }
404 }
405 
406 inline int bi_log2(const BigInteger& n)
407 {
408  int pw = 0;
409  BigInteger p = n >> 1U;
410  while (bi_compare_0(p) != 0) {
411  bi_rshift_ip(&p, 1U);
412  ++pw;
413  }
414  return pw;
415 }
416 
417 inline int bi_and_1(const BigInteger& left) { return left.bits[0] & 1; }
418 
419 inline BigInteger operator&(const BigInteger& left, const BigInteger& right)
420 {
421  BigInteger result;
422  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
423  result.bits[i] = left.bits[i] & right.bits[i];
424  }
425  return result;
426 }
427 
428 inline void bi_and_ip(BigInteger* left, const BigInteger& right)
429 {
430  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
431  left->bits[i] &= right.bits[i];
432  }
433 }
434 
435 inline BigInteger operator|(const BigInteger& left, const BigInteger& right)
436 {
437  BigInteger result;
438  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
439  result.bits[i] = left.bits[i] | right.bits[i];
440  }
441  return result;
442 }
443 
444 inline void bi_or_ip(BigInteger* left, const BigInteger& right)
445 {
446  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
447  left->bits[i] |= right.bits[i];
448  }
449 }
450 
451 inline BigInteger operator^(const BigInteger& left, const BigInteger& right)
452 {
453  BigInteger result;
454  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
455  result.bits[i] = left.bits[i] ^ right.bits[i];
456  }
457  return result;
458 }
459 
460 inline void bi_xor_ip(BigInteger* left, const BigInteger& right)
461 {
462  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
463  left->bits[i] ^= right.bits[i];
464  }
465 }
466 
467 inline BigInteger operator~(const BigInteger& left)
468 {
469  BigInteger result;
470  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
471  result.bits[i] = ~(left.bits[i]);
472  }
473  return result;
474 }
475 
476 inline void bi_not_ip(BigInteger* left)
477 {
478  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
479  left->bits[i] = ~(left->bits[i]);
480  }
481 }
482 
483 inline double bi_to_double(const BigInteger& in)
484 {
485  double toRet = 0.0;
486  for (int i = 0; i < BIG_INTEGER_WORD_SIZE; ++i) {
487  if (in.bits[i]) {
488  toRet += in.bits[i] * pow(2.0, BIG_INTEGER_WORD_BITS * i);
489  }
490  }
491  return toRet;
492 }
493 
494 inline bool operator==(const BigInteger& left, const BigInteger& right) { return bi_compare(left, right) == 0; }
495 inline bool operator<(const BigInteger& left, const BigInteger& right) { return bi_compare(left, right) < 0; }
496 inline bool operator<=(const BigInteger& left, const BigInteger& right) { return bi_compare(left, right) <= 0; }
497 inline bool operator>(const BigInteger& left, const BigInteger& right) { return bi_compare(left, right) > 0; }
498 inline bool operator>=(const BigInteger& left, const BigInteger& right) { return bi_compare(left, right) >= 0; }
499 
501 {
502  bi_increment(&a, 1U);
503  return a;
504 }
505 
507 {
508  bi_decrement(&a, 1U);
509  return a;
510 }
511 
517 
518 #if true
523 BigInteger operator*(const BigInteger& left, const BigInteger& right);
524 #else
529 BigInteger operator*(const BigInteger& left, const BigInteger& right);
530 #endif
531 
536 void bi_div_mod_small(
537  const BigInteger& left, BIG_INTEGER_HALF_WORD right, BigInteger* quotient, BIG_INTEGER_HALF_WORD* rmndr);
538 
543 void bi_div_mod(const BigInteger& left, const BigInteger& right, BigInteger* quotient, BigInteger* rmndr);
BigInteger operator~(const BigInteger &left)
Definition: big_integer.hpp:467
void bi_or_ip(BigInteger *left, const BigInteger &right)
Definition: big_integer.hpp:444
constexpr size_t BIG_INTEGER_BITS
Definition: big_integer.hpp:62
constexpr size_t BIG_INTEGER_HALF_WORD_BITS
Definition: big_integer.hpp:66
BigInteger operator--(BigInteger &a)
Definition: big_integer.hpp:506
void bi_decrement(BigInteger *pBigInt, const BIG_INTEGER_WORD &value)
Definition: big_integer.hpp:237
BigInteger operator&(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:419
BigInteger operator>>(const BigInteger &left, BIG_INTEGER_WORD right)
Definition: big_integer.hpp:364
void bi_increment(BigInteger *pBigInt, const BIG_INTEGER_WORD &value)
Definition: big_integer.hpp:220
void bi_div_mod_small(const BigInteger &left, BIG_INTEGER_HALF_WORD right, BigInteger *quotient, BIG_INTEGER_HALF_WORD *rmndr)
"Schoolbook division" (on half words) Complexity - O(x^2)
Definition: big_integer.cpp:182
#define BIG_INTEGER_WORD_POWER
Definition: big_integer.hpp:54
constexpr int BIG_INTEGER_MAX_WORD_INDEX
Definition: big_integer.hpp:68
int bi_and_1(const BigInteger &left)
Definition: big_integer.hpp:417
bool operator>=(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:498
BigInteger operator|(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:435
BigInteger operator+(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:170
void bi_add_ip(BigInteger *left, const BigInteger &right)
Definition: big_integer.hpp:182
bool operator>(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:497
BigInteger bi_rshift_word(const BigInteger &left, const BIG_INTEGER_WORD &rightMult)
Definition: big_integer.hpp:294
BigInteger operator^(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:451
int bi_compare_0(const BigInteger &left)
Definition: big_integer.hpp:140
BigInteger bi_lshift_word(const BigInteger &left, BIG_INTEGER_WORD rightMult)
Definition: big_integer.hpp:264
int bi_compare(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:125
void bi_and_ip(BigInteger *left, const BigInteger &right)
Definition: big_integer.hpp:428
constexpr int BIG_INTEGER_WORD_SIZE
Definition: big_integer.hpp:63
BigInteger operator<<(const BigInteger &left, BIG_INTEGER_WORD right)
Definition: big_integer.hpp:322
#define BIG_INTEGER_WORD_BITS
Definition: big_integer.hpp:53
#define BIG_INTEGER_WORD
Definition: big_integer.hpp:55
void bi_lshift_word_ip(BigInteger *left, BIG_INTEGER_WORD rightMult)
Definition: big_integer.hpp:278
bool operator==(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:494
double bi_to_double(const BigInteger &in)
Definition: big_integer.hpp:483
void bi_copy_ip(const BigInteger &in, BigInteger *out)
Definition: big_integer.hpp:118
BigInteger bi_copy(const BigInteger &in)
Definition: big_integer.hpp:109
void bi_rshift_word_ip(BigInteger *left, const BIG_INTEGER_WORD &rightMult)
Definition: big_integer.hpp:308
void bi_not_ip(BigInteger *left)
Definition: big_integer.hpp:476
int bi_compare_1(const BigInteger &left)
Definition: big_integer.hpp:151
bool operator<(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:495
void bi_set_0(BigInteger *p)
Definition: big_integer.hpp:102
void bi_xor_ip(BigInteger *left, const BigInteger &right)
Definition: big_integer.hpp:460
void bi_sub_ip(BigInteger *left, const BigInteger &right)
Definition: big_integer.hpp:207
BigInteger operator*(const BigInteger &left, BIG_INTEGER_HALF_WORD right)
"Schoolbook multiplication" (on half words) Complexity - O(x^2)
Definition: big_integer.cpp:39
int bi_log2(const BigInteger &n)
Definition: big_integer.hpp:406
constexpr int BIG_INTEGER_HALF_WORD_SIZE
Definition: big_integer.hpp:67
void bi_div_mod(const BigInteger &left, const BigInteger &right, BigInteger *quotient, BigInteger *rmndr)
Adapted from Qrack! (The fundamental algorithm was discovered before.) Complexity - O(log)
Definition: big_integer.cpp:221
BigInteger bi_load(BIG_INTEGER_WORD *a)
Definition: big_integer.hpp:254
void bi_lshift_ip(BigInteger *left, BIG_INTEGER_WORD right)
Definition: big_integer.hpp:344
bool operator<=(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:496
#define BIG_INTEGER_HALF_WORD
Definition: big_integer.hpp:56
struct BigInteger BigInteger
BigInteger operator-(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:195
void bi_rshift_ip(BigInteger *left, BIG_INTEGER_WORD right)
Definition: big_integer.hpp:386
BigInteger operator++(BigInteger &a)
Definition: big_integer.hpp:500
half pow(half x, half y)
Power function.
Definition: half.hpp:3738
MICROSOFT_QUANTUM_DECL void U(_In_ uintq sid, _In_ uintq q, _In_ double theta, _In_ double phi, _In_ double lambda)
(External API) 3-parameter unitary gate
Definition: pinvoke_api.cpp:1713
Definition: big_integer.hpp:70
BigInteger(const BIG_INTEGER_WORD &val)
Definition: big_integer.hpp:87
BIG_INTEGER_WORD bits[BIG_INTEGER_WORD_SIZE]
Definition: big_integer.hpp:71
BigInteger()
Definition: big_integer.hpp:73
BigInteger(const BigInteger &val)
Definition: big_integer.hpp:80