summaryrefslogtreecommitdiff
path: root/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/ntt.h
diff options
context:
space:
mode:
authorBen Sanders <ben@sanders.life>2026-08-02 09:49:25 -0400
committerBen Sanders <ben@sanders.life>2026-08-02 09:49:25 -0400
commitb41479c91e6685511c1f8ba8586106b322073b62 (patch)
treec9f1345999d754ae0a533849966427e792d9e68d /vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/ntt.h
parentcfaceeb9a6d1295f5754be211858155cd309acc2 (diff)
added statscounter code
Diffstat (limited to 'vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/ntt.h')
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/ntt.h191
1 files changed, 191 insertions, 0 deletions
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/ntt.h b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/ntt.h
new file mode 100644
index 0000000..bbd8376
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/ntt.h
@@ -0,0 +1,191 @@
+// NTT (Number Theoretic Transform) implementation for BigDecimal multiplication
+
+#define NTT_PRIMITIVE_ROOT 17
+#define NTT_PRIME_BASE1 24
+#define NTT_PRIME_BASE2 26
+#define NTT_PRIME_BASE3 29
+#define NTT_PRIME_SHIFT 27
+#define NTT_PRIME1 (((uint32_t)NTT_PRIME_BASE1 << NTT_PRIME_SHIFT) | 1)
+#define NTT_PRIME2 (((uint32_t)NTT_PRIME_BASE2 << NTT_PRIME_SHIFT) | 1)
+#define NTT_PRIME3 (((uint32_t)NTT_PRIME_BASE3 << NTT_PRIME_SHIFT) | 1)
+#define MAX_NTT32_BITS 27
+#define NTT_DECDIG_BASE 1000000000
+
+// Calculates base**ex % mod
+static uint32_t
+mod_pow(uint32_t base, uint32_t ex, uint32_t mod) {
+ uint32_t res = 1;
+ uint32_t bit = 1;
+ while (true) {
+ if (ex & bit) {
+ ex ^= bit;
+ res = ((uint64_t)res * base) % mod;
+ }
+ if (!ex) break;
+ base = ((uint64_t)base * base) % mod;
+ bit <<= 1;
+ }
+ return res;
+}
+
+// Recursively performs butterfly operations of NTT
+static void
+ntt_recursive(int size_bits, uint32_t *input, uint32_t *output, uint32_t *tmp, int depth, uint32_t r, uint32_t prime) {
+ if (depth > 0) {
+ ntt_recursive(size_bits, input, tmp, output, depth - 1, ((uint64_t)r * r) % prime, prime);
+ } else {
+ tmp = input;
+ }
+ uint32_t size_half = (uint32_t)1 << (size_bits - 1);
+ uint32_t stride = (uint32_t)1 << (size_bits - depth - 1);
+ uint32_t n = size_half / stride;
+ uint32_t rn = 1, rm = prime - 1;
+ for (uint32_t i = 0; i < n; i++) {
+ uint32_t *aptr = tmp + i * 2 * stride;
+ uint32_t *bptr = aptr + stride;
+ uint32_t *out1 = output + stride * i;
+ uint32_t *out2 = out1 + size_half;
+ for (uint32_t k = 0; k < stride; k++) {
+ uint32_t a = aptr[k], b = bptr[k];
+ out1[k] = (a + (uint64_t)rn * b) % prime;
+ out2[k] = (a + (uint64_t)rm * b) % prime;
+ }
+ rn = ((uint64_t)rn * r) % prime;
+ rm = ((uint64_t)rm * r) % prime;
+ }
+}
+
+/* Perform NTT on input array.
+ * base, shift: Represent the prime number as (base << shift | 1)
+ * r_base: Primitive root of unity modulo prime
+ * size_bits: log2 of the size of the input array. Should be less or equal to shift
+ * input: input array of size (1 << size_bits)
+ */
+static void
+ntt(int size_bits, uint32_t *input, uint32_t *output, uint32_t *tmp, int r_base, int base, int shift, int dir) {
+ uint32_t size = (uint32_t)1 << size_bits;
+ uint32_t prime = ((uint32_t)base << shift) | 1;
+
+ // rmax**(1 << shift) % prime == 1
+ // r**size % prime == 1
+ uint32_t rmax = mod_pow((uint32_t)r_base, (uint32_t)base, prime);
+ uint32_t r = mod_pow(rmax, (uint32_t)1 << (shift - size_bits), prime);
+
+ if (dir < 0) r = mod_pow(r, prime - 2, prime);
+ ntt_recursive(size_bits, input, output, tmp, size_bits - 1, r, prime);
+ if (dir < 0) {
+ uint32_t n_inv = mod_pow((uint32_t)size, prime - 2, prime);
+ for (uint32_t i = 0; i < size; i++) {
+ output[i] = ((uint64_t)output[i] * n_inv) % prime;
+ }
+ }
+}
+
+/* Calculate c that satisfies: c % PRIME1 == mod1 && c % PRIME2 == mod2 && c % PRIME3 == mod3
+ * c = (mod1 * 35002755423056150739595925972 + mod2 * 14584479687667766215746868453 + mod3 * 37919651490985126265126719818) % (PRIME1 * PRIME2 * PRIME3)
+ * Assume c <= 999999999**2*(1<<27)
+ */
+static inline void
+mod_restore_prime_24_26_29_shift_27(uint32_t mod1, uint32_t mod2, uint32_t mod3, uint32_t *digits) {
+ // Use mixed radix notation to eliminate modulo by PRIME1 * PRIME2 * PRIME3
+ // [DIG0, DIG1, DIG2] = DIG0 + DIG1 * PRIME1 + DIG2 * PRIME1 * PRIME2
+ // DIG0: 0...PRIME1, DIG1: 0...PRIME2, DIG2: 0...PRIME3
+ // 35002755423056150739595925972 = [1, 3489660916, 3113851359]
+ // 14584479687667766215746868453 = [0, 13, 1297437912]
+ // 37919651490985126265126719818 = [0, 0, 3373338954]
+ uint64_t c0 = mod1;
+ uint64_t c1 = (uint64_t)mod2 * 13 + (uint64_t)mod1 * 3489660916;
+ uint64_t c2 = (uint64_t)mod3 * 3373338954 % NTT_PRIME3 + (uint64_t)mod2 * 1297437912 % NTT_PRIME3 + (uint64_t)mod1 * 3113851359 % NTT_PRIME3;
+ c2 += c1 / NTT_PRIME2;
+ c1 %= NTT_PRIME2;
+ c2 %= NTT_PRIME3;
+ // Base conversion. c fits in 3 digits.
+ c1 += c2 % NTT_DECDIG_BASE * NTT_PRIME2;
+ c0 += c1 % NTT_DECDIG_BASE * NTT_PRIME1;
+ c1 /= NTT_DECDIG_BASE;
+ digits[0] = c0 % NTT_DECDIG_BASE;
+ c0 /= NTT_DECDIG_BASE;
+ c1 += c2 / NTT_DECDIG_BASE % NTT_DECDIG_BASE * NTT_PRIME2;
+ c0 += c1 % NTT_DECDIG_BASE * NTT_PRIME1;
+ c1 /= NTT_DECDIG_BASE;
+ digits[1] = c0 % NTT_DECDIG_BASE;
+ digits[2] = (uint32_t)(c0 / NTT_DECDIG_BASE + c1 % NTT_DECDIG_BASE * NTT_PRIME1);
+}
+
+/*
+ * NTT multiplication
+ * Uses three NTTs with mod (24 << 27 | 1), (26 << 27 | 1), and (29 << 27 | 1)
+ */
+static void
+ntt_multiply(size_t a_size, size_t b_size, uint32_t *a, uint32_t *b, uint32_t *c) {
+ if (a_size < b_size) {
+ ntt_multiply(b_size, a_size, b, a, c);
+ return;
+ }
+
+ int ntt_size_bits = (int)bit_length(b_size - 1) + 1;
+ if (ntt_size_bits > MAX_NTT32_BITS) {
+ rb_raise(rb_eArgError, "Multiply size too large");
+ }
+
+ // To calculate large_a * small_b faster, split into several batches.
+ uint32_t ntt_size = (uint32_t)1 << ntt_size_bits;
+ uint32_t batch_size = ntt_size - (uint32_t)b_size;
+ uint32_t batch_count = (uint32_t)((a_size + batch_size - 1) / batch_size);
+
+ uint32_t *mem = ruby_xcalloc(ntt_size * 9, sizeof(uint32_t));
+ uint32_t *ntt1 = mem;
+ uint32_t *ntt2 = mem + ntt_size;
+ uint32_t *ntt3 = mem + ntt_size * 2;
+ uint32_t *tmp1 = mem + ntt_size * 3;
+ uint32_t *tmp2 = mem + ntt_size * 4;
+ uint32_t *tmp3 = mem + ntt_size * 5;
+ uint32_t *conv1 = mem + ntt_size * 6;
+ uint32_t *conv2 = mem + ntt_size * 7;
+ uint32_t *conv3 = mem + ntt_size * 8;
+
+ // Calculate NTT for b in three primes. Result is reused for each batch of a.
+ memcpy(tmp1, b, b_size * sizeof(uint32_t));
+ memset(tmp1 + b_size, 0, (ntt_size - b_size) * sizeof(uint32_t));
+ ntt(ntt_size_bits, tmp1, ntt1, tmp2, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE1, NTT_PRIME_SHIFT, +1);
+ ntt(ntt_size_bits, tmp1, ntt2, tmp2, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE2, NTT_PRIME_SHIFT, +1);
+ ntt(ntt_size_bits, tmp1, ntt3, tmp2, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE3, NTT_PRIME_SHIFT, +1);
+
+ memset(c, 0, (a_size + b_size) * sizeof(uint32_t));
+ for (uint32_t idx = 0; idx < batch_count; idx++) {
+ uint32_t len = idx == batch_count - 1 ? (uint32_t)a_size - idx * batch_size : batch_size;
+ memcpy(tmp1, a + idx * batch_size, len * sizeof(uint32_t));
+ memset(tmp1 + len, 0, (ntt_size - len) * sizeof(uint32_t));
+ // Calculate convolution for this batch in three primes
+ ntt(ntt_size_bits, tmp1, tmp2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE1, NTT_PRIME_SHIFT, +1);
+ for (uint32_t i = 0; i < ntt_size; i++) tmp2[i] = ((uint64_t)tmp2[i] * ntt1[i]) % NTT_PRIME1;
+ ntt(ntt_size_bits, tmp2, conv1, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE1, NTT_PRIME_SHIFT, -1);
+ ntt(ntt_size_bits, tmp1, tmp2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE2, NTT_PRIME_SHIFT, +1);
+ for (uint32_t i = 0; i < ntt_size; i++) tmp2[i] = ((uint64_t)tmp2[i] * ntt2[i]) % NTT_PRIME2;
+ ntt(ntt_size_bits, tmp2, conv2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE2, NTT_PRIME_SHIFT, -1);
+ ntt(ntt_size_bits, tmp1, tmp2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE3, NTT_PRIME_SHIFT, +1);
+ for (uint32_t i = 0; i < ntt_size; i++) tmp2[i] = ((uint64_t)tmp2[i] * ntt3[i]) % NTT_PRIME3;
+ ntt(ntt_size_bits, tmp2, conv3, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE3, NTT_PRIME_SHIFT, -1);
+
+ // Restore the original convolution value from three convolutions calculated in three primes.
+ // Each convolution value is maximum 999999999**2*(1<<27)/2
+ for (uint32_t i = 0; i < ntt_size; i++) {
+ uint32_t dig[3];
+ mod_restore_prime_24_26_29_shift_27(conv1[i], conv2[i], conv3[i], dig);
+ // Maximum values of dig[0], dig[1], and dig[2] are 999999999, 999999999 and 67108863 respectively
+ // Maximum overlapped sum (considering overlaps between 2 batches) is less than 4134217722
+ // so this sum doesn't overflow uint32_t.
+ for (int j = 0; j < 3; j++) {
+ // Index check: if dig[j] is non-zero, assign index is within valid range.
+ if (dig[j]) c[idx * batch_size + i + 1 - (uint32_t)j] += dig[j];
+ }
+ }
+ }
+ uint32_t carry = 0;
+ for (int32_t i = (int32_t)(a_size + b_size - 1); i >= 0; i--) {
+ uint32_t v = c[i] + carry;
+ c[i] = v % NTT_DECDIG_BASE;
+ carry = v / NTT_DECDIG_BASE;
+ }
+ ruby_xfree(mem);
+}