2#include "prism/internal/bignum.h"
13#define PM_BIGNUM_KARATSUBA_THRESHOLD 24
22pm_bignum_base_words_add(uint64_t base, uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length) {
26 for (; index < right_length; index++) {
27 uint64_t sum = (uint64_t) left[index] + right[index] + carry;
29 left[index] = (uint32_t) (carry ? sum - base : sum);
32 for (; carry != 0 && index < left_length; index++) {
33 uint64_t sum = (uint64_t) left[index] + 1;
35 left[index] = (uint32_t) (carry ? 0 : sum);
46pm_bignum_base_words_subtract(uint64_t base, uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length) {
51 for (; index < right_length; index++) {
52 uint64_t subtrahend = (uint64_t) right[index] + borrow;
53 borrow = left[index] < subtrahend;
54 left[index] = (uint32_t) (borrow ? left[index] + base - subtrahend : left[index] - subtrahend);
57 for (; borrow != 0; index++) {
58 assert(index < left_length);
59 borrow = left[index] == 0;
60 left[index] = (uint32_t) (borrow ? base - 1 : left[index] - 1);
69pm_bignum_words_add(uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length) {
70 return pm_bignum_base_words_add(PM_BIGNUM_BINARY_BASE, left, left_length, right, right_length);
78pm_bignum_decimal_words_add(uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length) {
79 return pm_bignum_base_words_add(PM_BIGNUM_DECIMAL_BASE, left, left_length, right, right_length);
87pm_bignum_words_subtract(uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length) {
88 pm_bignum_base_words_subtract(PM_BIGNUM_BINARY_BASE, left, left_length, right, right_length);
96pm_bignum_decimal_words_subtract(uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length) {
97 pm_bignum_base_words_subtract(PM_BIGNUM_DECIMAL_BASE, left, left_length, right, right_length);
107pm_bignum_words_multiply_schoolbook(uint32_t *result,
const uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length) {
108 memset(result, 0,
sizeof(uint32_t) * (left_length + right_length));
110 for (uint32_t right_index = 0; right_index < right_length; right_index++) {
113 for (uint32_t left_index = 0; left_index < left_length; left_index++) {
114 carry += (uint64_t) left[left_index] * right[right_index] + result[left_index + right_index];
115 result[left_index + right_index] = (uint32_t) carry;
119 result[right_index + left_length] = (uint32_t) carry;
129#define PM_BIGNUM_DECIMAL_PRODUCTS 18
141pm_bignum_decimal_words_multiply_schoolbook(uint32_t *result,
const uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length) {
142 if (left_length == 0 || right_length == 0) {
143 memset(result, 0,
sizeof(uint32_t) * (left_length + right_length));
152 for (uint32_t index = 0; index < left_length + right_length - 1; index++) {
153 uint32_t left_start = index < right_length ? 0 : index - right_length + 1;
154 uint32_t left_end = index < left_length ? index + 1 : left_length;
158 uint32_t products = 0;
160 for (uint32_t left_index = left_start; left_index < left_end; left_index++) {
161 low += (uint64_t) left[left_index] * right[index - left_index];
163 if (++products == PM_BIGNUM_DECIMAL_PRODUCTS) {
164 high += low / PM_BIGNUM_DECIMAL_BASE;
165 low %= PM_BIGNUM_DECIMAL_BASE;
170 low += carry % PM_BIGNUM_DECIMAL_BASE;
171 high += carry / PM_BIGNUM_DECIMAL_BASE;
173 result[index] = (uint32_t) (low % PM_BIGNUM_DECIMAL_BASE);
174 carry = high + low / PM_BIGNUM_DECIMAL_BASE;
179 assert(carry < PM_BIGNUM_DECIMAL_BASE);
180 result[left_length + right_length - 1] = (uint32_t) carry;
183static void pm_bignum_words_multiply(uint32_t *result,
const uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length,
pm_bignum_scratch_t *scratch);
184static void pm_bignum_decimal_words_multiply(uint32_t *result,
const uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length,
pm_bignum_scratch_t *scratch);
197pm_bignum_radix_add(uint64_t base, uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length) {
198 return base == PM_BIGNUM_DECIMAL_BASE ? pm_bignum_decimal_words_add(left, left_length, right, right_length) : pm_bignum_words_add(left, left_length, right, right_length);
205pm_bignum_radix_subtract(uint64_t base, uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length) {
206 if (base == PM_BIGNUM_DECIMAL_BASE) {
207 pm_bignum_decimal_words_subtract(left, left_length, right, right_length);
209 pm_bignum_words_subtract(left, left_length, right, right_length);
217pm_bignum_radix_multiply_schoolbook(uint64_t base, uint32_t *result,
const uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length) {
218 if (base == PM_BIGNUM_DECIMAL_BASE) {
219 pm_bignum_decimal_words_multiply_schoolbook(result, left, left_length, right, right_length);
221 pm_bignum_words_multiply_schoolbook(result, left, left_length, right, right_length);
229pm_bignum_radix_multiply(uint64_t base, uint32_t *result,
const uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length,
pm_bignum_scratch_t *scratch) {
230 if (base == PM_BIGNUM_DECIMAL_BASE) {
231 pm_bignum_decimal_words_multiply(result, left, left_length, right, right_length, scratch);
233 pm_bignum_words_multiply(result, left, left_length, right, right_length, scratch);
249pm_bignum_radix_karatsuba(uint64_t base, uint32_t *result,
const uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length,
pm_bignum_scratch_t *scratch) {
250 if (left_length < right_length) {
251 const uint32_t *words = left;
255 uint32_t length = left_length;
256 left_length = right_length;
257 right_length = length;
260 if (right_length < PM_BIGNUM_KARATSUBA_THRESHOLD) {
261 pm_bignum_radix_multiply_schoolbook(base, result, left, left_length, right, right_length);
265 uint32_t *saved = scratch->cursor;
270 if (left_length >= 2 * right_length) {
271 memset(result, 0,
sizeof(uint32_t) * (left_length + right_length));
272 uint32_t *product = pm_bignum_scratch_take(scratch, 2 * right_length);
274 for (uint32_t offset = 0; offset < left_length; offset += right_length) {
275 uint32_t piece = left_length - offset < right_length ? left_length - offset : right_length;
276 pm_bignum_radix_multiply(base, product, left + offset, piece, right, right_length, scratch);
277 pm_bignum_radix_add(base, result + offset, left_length + right_length - offset, product, piece + right_length);
280 scratch->cursor = saved;
284 uint32_t half = right_length / 2;
285 uint32_t left_high_length = left_length - half;
286 uint32_t right_high_length = right_length - half;
288 pm_bignum_radix_multiply(base, result, left, half, right, half, scratch);
289 pm_bignum_radix_multiply(base, result + 2 * half, left + half, left_high_length, right + half, right_high_length, scratch);
293 uint32_t *left_sum = pm_bignum_scratch_take(scratch, left_high_length + 1);
294 memcpy(left_sum, left + half,
sizeof(uint32_t) * left_high_length);
295 left_sum[left_high_length] = 0;
296 pm_bignum_radix_add(base, left_sum, left_high_length + 1, left, half);
298 uint32_t *right_sum = pm_bignum_scratch_take(scratch, right_high_length + 1);
299 memcpy(right_sum, right + half,
sizeof(uint32_t) * right_high_length);
300 right_sum[right_high_length] = 0;
301 pm_bignum_radix_add(base, right_sum, right_high_length + 1, right, half);
303 uint32_t middle_length = left_high_length + right_high_length + 2;
304 uint32_t *middle = pm_bignum_scratch_take(scratch, middle_length);
305 pm_bignum_radix_multiply(base, middle, left_sum, left_high_length + 1, right_sum, right_high_length + 1, scratch);
306 pm_bignum_radix_subtract(base, middle, middle_length, result, 2 * half);
307 pm_bignum_radix_subtract(base, middle, middle_length, result + 2 * half, left_high_length + right_high_length);
309 while (middle_length > 0 && middle[middle_length - 1] == 0) middle_length--;
310 pm_bignum_radix_add(base, result + half, left_length + right_length - half, middle, middle_length);
312 scratch->cursor = saved;
320pm_bignum_words_multiply(uint32_t *result,
const uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length,
pm_bignum_scratch_t *scratch) {
321 pm_bignum_radix_karatsuba(PM_BIGNUM_BINARY_BASE, result, left, left_length, right, right_length, scratch);
329pm_bignum_decimal_words_multiply(uint32_t *result,
const uint32_t *left, uint32_t left_length,
const uint32_t *right, uint32_t right_length,
pm_bignum_scratch_t *scratch) {
330 pm_bignum_radix_karatsuba(PM_BIGNUM_DECIMAL_BASE, result, left, left_length, right, right_length, scratch);
340 if (left->length < right->length) {
341 memset(left->words + left->length, 0,
sizeof(uint32_t) * (right->length - left->length));
342 left->length = right->length;
345 uint32_t carry = pm_bignum_radix_add(base, left->words, left->length, right->words, right->length);
346 if (carry != 0) left->words[left->length++] = carry;
355 uint32_t length = left->length + right->length;
356 pm_bignum_radix_multiply(base, result->words, left->words, left->length, right->words, right->length, scratch);
358 while (length > 0 && result->words[length - 1] == 0) length--;
359 result->length = length;
368 pm_bignum_radix_add_bignum(PM_BIGNUM_BINARY_BASE, left, right);
378 pm_bignum_radix_multiply_bignum(PM_BIGNUM_BINARY_BASE, result, left, right, scratch);
387 pm_bignum_radix_add_bignum(PM_BIGNUM_DECIMAL_BASE, left, right);
397 pm_bignum_radix_multiply_bignum(PM_BIGNUM_DECIMAL_BASE, result, left, right, scratch);
#define PRISM_FORCE_INLINE
Force a function to be inlined at every call site.