Description
Instead of having the number's magnitude stored in a string, it would be much more efficient, in terms of both time and space, to have it stored in a vector of unsigned 64-bit integers (std::vector<uint64_t>
). That is, store a number's digits in base 264.
The following table lists how the number's magnitude will be represented in base 264:
Magnitude | Representation | Comment |
---|---|---|
0 | {0} |
0⋅(264)0 |
1 | {1} |
1⋅(264)0 |
2 | {2} |
2⋅(264)0 |
264 - 1 | {18446744073709551615} |
18446744073709551615⋅(264)0 |
264 | {0, 1} |
1⋅(264)1 |
264 + 1 | {1, 1} |
1⋅(264)0 + 1⋅(264)1 |
264 + 2 | {2, 1} |
2⋅(264)0 + 1⋅(264)1 |
265 | {0, 2} |
2⋅(264)1 |
550 | {11670147153572883801, 4814824860968089} |
11670147153572883801⋅(264)0 + 4814824860968089⋅(264)1 |
2128 | {0, 0, 1} |
1⋅(264)2 |
2192 | {0, 0, 0, 1} |
1⋅(264)3 |
2256 | {0, 0, 0, 0, 1} |
1⋅(264)4 |
The way how it could speed up performance is that, for example, when adding two BigInt
s, instead of adding their corresponding decimal digits together, their corresponding base 264 digits will be added, each digit in a single operation. Moreover, this addition (or any other arithmetic operation) of vectors can be vectorised by using SSE or AVX, which would further improve performance by a few folds.
Say, for instance, that you were adding two 5000 digit numbers. In base 10 they have 5000 digits, which means that it would take 5000 operations to add them together. Instead, if they were in base 264, they would have 260 digits, and would therefore require only 260 operations. Using AVX-512, vectors with up to 8 64-bit digits can be added together in a single operation. Which means that by using vectorized operations, two 5000 digit numbers could be added using just 33 operations.