bigdecimal 3.3.1 → 4.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -58,7 +58,7 @@ char *BigDecimal_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, c
58
58
 
59
59
  #ifndef HAVE_RB_COMPLEX_REAL
60
60
  static inline VALUE
61
- rb_complex_real(VALUE cmp)
61
+ rb_complex_real_fallback(VALUE cmp)
62
62
  {
63
63
  #ifdef RCOMPLEX
64
64
  return RCOMPLEX(cmp)->real;
@@ -66,11 +66,12 @@ rb_complex_real(VALUE cmp)
66
66
  return rb_funcall(cmp, rb_intern("real"), 0);
67
67
  #endif
68
68
  }
69
+ #define rb_complex_real rb_complex_real_fallback
69
70
  #endif
70
71
 
71
72
  #ifndef HAVE_RB_COMPLEX_IMAG
72
73
  static inline VALUE
73
- rb_complex_imag(VALUE cmp)
74
+ rb_complex_imag_fallback(VALUE cmp)
74
75
  {
75
76
  # ifdef RCOMPLEX
76
77
  return RCOMPLEX(cmp)->imag;
@@ -78,6 +79,7 @@ rb_complex_imag(VALUE cmp)
78
79
  return rb_funcall(cmp, rb_intern("imag"), 0);
79
80
  # endif
80
81
  }
82
+ #define rb_complex_imag rb_complex_imag_fallback
81
83
  #endif
82
84
 
83
85
  /* st */
@@ -0,0 +1,191 @@
1
+ // NTT (Number Theoretic Transform) implementation for BigDecimal multiplication
2
+
3
+ #define NTT_PRIMITIVE_ROOT 17
4
+ #define NTT_PRIME_BASE1 24
5
+ #define NTT_PRIME_BASE2 26
6
+ #define NTT_PRIME_BASE3 29
7
+ #define NTT_PRIME_SHIFT 27
8
+ #define NTT_PRIME1 (((uint32_t)NTT_PRIME_BASE1 << NTT_PRIME_SHIFT) | 1)
9
+ #define NTT_PRIME2 (((uint32_t)NTT_PRIME_BASE2 << NTT_PRIME_SHIFT) | 1)
10
+ #define NTT_PRIME3 (((uint32_t)NTT_PRIME_BASE3 << NTT_PRIME_SHIFT) | 1)
11
+ #define MAX_NTT32_BITS 27
12
+ #define NTT_DECDIG_BASE 1000000000
13
+
14
+ // Calculates base**ex % mod
15
+ static uint32_t
16
+ mod_pow(uint32_t base, uint32_t ex, uint32_t mod) {
17
+ uint32_t res = 1;
18
+ uint32_t bit = 1;
19
+ while (true) {
20
+ if (ex & bit) {
21
+ ex ^= bit;
22
+ res = ((uint64_t)res * base) % mod;
23
+ }
24
+ if (!ex) break;
25
+ base = ((uint64_t)base * base) % mod;
26
+ bit <<= 1;
27
+ }
28
+ return res;
29
+ }
30
+
31
+ // Recursively performs butterfly operations of NTT
32
+ static void
33
+ ntt_recursive(int size_bits, uint32_t *input, uint32_t *output, uint32_t *tmp, int depth, uint32_t r, uint32_t prime) {
34
+ if (depth > 0) {
35
+ ntt_recursive(size_bits, input, tmp, output, depth - 1, ((uint64_t)r * r) % prime, prime);
36
+ } else {
37
+ tmp = input;
38
+ }
39
+ uint32_t size_half = (uint32_t)1 << (size_bits - 1);
40
+ uint32_t stride = (uint32_t)1 << (size_bits - depth - 1);
41
+ uint32_t n = size_half / stride;
42
+ uint32_t rn = 1, rm = prime - 1;
43
+ for (uint32_t i = 0; i < n; i++) {
44
+ uint32_t *aptr = tmp + i * 2 * stride;
45
+ uint32_t *bptr = aptr + stride;
46
+ uint32_t *out1 = output + stride * i;
47
+ uint32_t *out2 = out1 + size_half;
48
+ for (uint32_t k = 0; k < stride; k++) {
49
+ uint32_t a = aptr[k], b = bptr[k];
50
+ out1[k] = (a + (uint64_t)rn * b) % prime;
51
+ out2[k] = (a + (uint64_t)rm * b) % prime;
52
+ }
53
+ rn = ((uint64_t)rn * r) % prime;
54
+ rm = ((uint64_t)rm * r) % prime;
55
+ }
56
+ }
57
+
58
+ /* Perform NTT on input array.
59
+ * base, shift: Represent the prime number as (base << shift | 1)
60
+ * r_base: Primitive root of unity modulo prime
61
+ * size_bits: log2 of the size of the input array. Should be less or equal to shift
62
+ * input: input array of size (1 << size_bits)
63
+ */
64
+ static void
65
+ ntt(int size_bits, uint32_t *input, uint32_t *output, uint32_t *tmp, int r_base, int base, int shift, int dir) {
66
+ uint32_t size = (uint32_t)1 << size_bits;
67
+ uint32_t prime = ((uint32_t)base << shift) | 1;
68
+
69
+ // rmax**(1 << shift) % prime == 1
70
+ // r**size % prime == 1
71
+ uint32_t rmax = mod_pow((uint32_t)r_base, (uint32_t)base, prime);
72
+ uint32_t r = mod_pow(rmax, (uint32_t)1 << (shift - size_bits), prime);
73
+
74
+ if (dir < 0) r = mod_pow(r, prime - 2, prime);
75
+ ntt_recursive(size_bits, input, output, tmp, size_bits - 1, r, prime);
76
+ if (dir < 0) {
77
+ uint32_t n_inv = mod_pow((uint32_t)size, prime - 2, prime);
78
+ for (uint32_t i = 0; i < size; i++) {
79
+ output[i] = ((uint64_t)output[i] * n_inv) % prime;
80
+ }
81
+ }
82
+ }
83
+
84
+ /* Calculate c that satisfies: c % PRIME1 == mod1 && c % PRIME2 == mod2 && c % PRIME3 == mod3
85
+ * c = (mod1 * 35002755423056150739595925972 + mod2 * 14584479687667766215746868453 + mod3 * 37919651490985126265126719818) % (PRIME1 * PRIME2 * PRIME3)
86
+ * Assume c <= 999999999**2*(1<<27)
87
+ */
88
+ static inline void
89
+ mod_restore_prime_24_26_29_shift_27(uint32_t mod1, uint32_t mod2, uint32_t mod3, uint32_t *digits) {
90
+ // Use mixed radix notation to eliminate modulo by PRIME1 * PRIME2 * PRIME3
91
+ // [DIG0, DIG1, DIG2] = DIG0 + DIG1 * PRIME1 + DIG2 * PRIME1 * PRIME2
92
+ // DIG0: 0...PRIME1, DIG1: 0...PRIME2, DIG2: 0...PRIME3
93
+ // 35002755423056150739595925972 = [1, 3489660916, 3113851359]
94
+ // 14584479687667766215746868453 = [0, 13, 1297437912]
95
+ // 37919651490985126265126719818 = [0, 0, 3373338954]
96
+ uint64_t c0 = mod1;
97
+ uint64_t c1 = (uint64_t)mod2 * 13 + (uint64_t)mod1 * 3489660916;
98
+ uint64_t c2 = (uint64_t)mod3 * 3373338954 % NTT_PRIME3 + (uint64_t)mod2 * 1297437912 % NTT_PRIME3 + (uint64_t)mod1 * 3113851359 % NTT_PRIME3;
99
+ c2 += c1 / NTT_PRIME2;
100
+ c1 %= NTT_PRIME2;
101
+ c2 %= NTT_PRIME3;
102
+ // Base conversion. c fits in 3 digits.
103
+ c1 += c2 % NTT_DECDIG_BASE * NTT_PRIME2;
104
+ c0 += c1 % NTT_DECDIG_BASE * NTT_PRIME1;
105
+ c1 /= NTT_DECDIG_BASE;
106
+ digits[0] = c0 % NTT_DECDIG_BASE;
107
+ c0 /= NTT_DECDIG_BASE;
108
+ c1 += c2 / NTT_DECDIG_BASE % NTT_DECDIG_BASE * NTT_PRIME2;
109
+ c0 += c1 % NTT_DECDIG_BASE * NTT_PRIME1;
110
+ c1 /= NTT_DECDIG_BASE;
111
+ digits[1] = c0 % NTT_DECDIG_BASE;
112
+ digits[2] = (uint32_t)(c0 / NTT_DECDIG_BASE + c1 % NTT_DECDIG_BASE * NTT_PRIME1);
113
+ }
114
+
115
+ /*
116
+ * NTT multiplication
117
+ * Uses three NTTs with mod (24 << 27 | 1), (26 << 27 | 1), and (29 << 27 | 1)
118
+ */
119
+ static void
120
+ ntt_multiply(size_t a_size, size_t b_size, uint32_t *a, uint32_t *b, uint32_t *c) {
121
+ if (a_size < b_size) {
122
+ ntt_multiply(b_size, a_size, b, a, c);
123
+ return;
124
+ }
125
+
126
+ int ntt_size_bits = (int)bit_length(b_size - 1) + 1;
127
+ if (ntt_size_bits > MAX_NTT32_BITS) {
128
+ rb_raise(rb_eArgError, "Multiply size too large");
129
+ }
130
+
131
+ // To calculate large_a * small_b faster, split into several batches.
132
+ uint32_t ntt_size = (uint32_t)1 << ntt_size_bits;
133
+ uint32_t batch_size = ntt_size - (uint32_t)b_size;
134
+ uint32_t batch_count = (uint32_t)((a_size + batch_size - 1) / batch_size);
135
+
136
+ uint32_t *mem = ruby_xcalloc(ntt_size * 9, sizeof(uint32_t));
137
+ uint32_t *ntt1 = mem;
138
+ uint32_t *ntt2 = mem + ntt_size;
139
+ uint32_t *ntt3 = mem + ntt_size * 2;
140
+ uint32_t *tmp1 = mem + ntt_size * 3;
141
+ uint32_t *tmp2 = mem + ntt_size * 4;
142
+ uint32_t *tmp3 = mem + ntt_size * 5;
143
+ uint32_t *conv1 = mem + ntt_size * 6;
144
+ uint32_t *conv2 = mem + ntt_size * 7;
145
+ uint32_t *conv3 = mem + ntt_size * 8;
146
+
147
+ // Calculate NTT for b in three primes. Result is reused for each batch of a.
148
+ memcpy(tmp1, b, b_size * sizeof(uint32_t));
149
+ memset(tmp1 + b_size, 0, (ntt_size - b_size) * sizeof(uint32_t));
150
+ ntt(ntt_size_bits, tmp1, ntt1, tmp2, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE1, NTT_PRIME_SHIFT, +1);
151
+ ntt(ntt_size_bits, tmp1, ntt2, tmp2, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE2, NTT_PRIME_SHIFT, +1);
152
+ ntt(ntt_size_bits, tmp1, ntt3, tmp2, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE3, NTT_PRIME_SHIFT, +1);
153
+
154
+ memset(c, 0, (a_size + b_size) * sizeof(uint32_t));
155
+ for (uint32_t idx = 0; idx < batch_count; idx++) {
156
+ uint32_t len = idx == batch_count - 1 ? (uint32_t)a_size - idx * batch_size : batch_size;
157
+ memcpy(tmp1, a + idx * batch_size, len * sizeof(uint32_t));
158
+ memset(tmp1 + len, 0, (ntt_size - len) * sizeof(uint32_t));
159
+ // Calculate convolution for this batch in three primes
160
+ ntt(ntt_size_bits, tmp1, tmp2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE1, NTT_PRIME_SHIFT, +1);
161
+ for (uint32_t i = 0; i < ntt_size; i++) tmp2[i] = ((uint64_t)tmp2[i] * ntt1[i]) % NTT_PRIME1;
162
+ ntt(ntt_size_bits, tmp2, conv1, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE1, NTT_PRIME_SHIFT, -1);
163
+ ntt(ntt_size_bits, tmp1, tmp2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE2, NTT_PRIME_SHIFT, +1);
164
+ for (uint32_t i = 0; i < ntt_size; i++) tmp2[i] = ((uint64_t)tmp2[i] * ntt2[i]) % NTT_PRIME2;
165
+ ntt(ntt_size_bits, tmp2, conv2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE2, NTT_PRIME_SHIFT, -1);
166
+ ntt(ntt_size_bits, tmp1, tmp2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE3, NTT_PRIME_SHIFT, +1);
167
+ for (uint32_t i = 0; i < ntt_size; i++) tmp2[i] = ((uint64_t)tmp2[i] * ntt3[i]) % NTT_PRIME3;
168
+ ntt(ntt_size_bits, tmp2, conv3, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE3, NTT_PRIME_SHIFT, -1);
169
+
170
+ // Restore the original convolution value from three convolutions calculated in three primes.
171
+ // Each convolution value is maximum 999999999**2*(1<<27)/2
172
+ for (uint32_t i = 0; i < ntt_size; i++) {
173
+ uint32_t dig[3];
174
+ mod_restore_prime_24_26_29_shift_27(conv1[i], conv2[i], conv3[i], dig);
175
+ // Maximum values of dig[0], dig[1], and dig[2] are 999999999, 999999999 and 67108863 respectively
176
+ // Maximum overlapped sum (considering overlaps between 2 batches) is less than 4134217722
177
+ // so this sum doesn't overflow uint32_t.
178
+ for (int j = 0; j < 3; j++) {
179
+ // Index check: if dig[j] is non-zero, assign index is within valid range.
180
+ if (dig[j]) c[idx * batch_size + i + 1 - (uint32_t)j] += dig[j];
181
+ }
182
+ }
183
+ }
184
+ uint32_t carry = 0;
185
+ for (int32_t i = (int32_t)(a_size + b_size - 1); i >= 0; i--) {
186
+ uint32_t v = c[i] + carry;
187
+ c[i] = v % NTT_DECDIG_BASE;
188
+ carry = v / NTT_DECDIG_BASE;
189
+ }
190
+ ruby_xfree(mem);
191
+ }
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'bigdecimal'
4
4
 
5
+ warn "'bigdecimal/jacobian' is deprecated and will be removed in a future release."
6
+
5
7
  # require 'bigdecimal/jacobian'
6
8
  #
7
9
  # Provides methods to compute the Jacobian matrix of a set of equations at a
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: false
2
2
  require 'bigdecimal'
3
3
 
4
+ warn "'bigdecimal/ludcmp' is deprecated and will be removed in a future release."
5
+
4
6
  #
5
7
  # Solves a*x = b for x, using LU decomposition.
6
8
  #
@@ -0,0 +1,291 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BigMath
4
+ # Bit-burst implementation of BigMath.erf and BigMath.erfc.
5
+ #
6
+ # Both functions share the same incremental update: given erf(x0+...+xk) (or erfc),
7
+ # extend to erf(x0+...+xk+x_{k+1}) by adding (or, for erfc, subtracting) the Taylor
8
+ # expansion of the difference function
9
+ # g(t) := (erf(t + a) - erf(a)) * exp(a**2) * sqrt(pi) / 2 with a = x0+...+xk
10
+ # which satisfies the homogeneous ODE g''(t) + 2*(t+a)*g'(t) = 0.
11
+ # Each step uses binary splitting on the 3-term recurrence of g's Taylor coefficients;
12
+ # split widths x1, x2, ... double in digits, giving quasi-linear total cost.
13
+ #
14
+ # Only the bit-burst seed differs between the two:
15
+ # erf : seed = erf(x0) via Taylor expansion at 0
16
+ # erfc : seed = erfc(x0) via asymptotic expansion (requires x0 large enough;
17
+ # returns nil if asymptotic cannot reach the requested precision, in which
18
+ # case erfc(x) is recovered from 1 - erf(x) with extra digits to absorb
19
+ # cancellation)
20
+ #
21
+ # Edge cases (after symmetry erf(-x) = -erf(x)):
22
+ # x == 0 : erf = 0
23
+ # x > 5e9 : erf = 1, erfc underflows
24
+ # x < 0.5 (erfc only) : compute via 1 - erf to avoid unnecessary work
25
+ module Erf # :nodoc:
26
+
27
+ # Calculates erf with given precision.
28
+ def self.erf(x, prec)
29
+ prec = BigDecimal::Internal.coerce_validate_prec(prec, :erf)
30
+ x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :erf)
31
+ return BigDecimal::Internal.nan_computation_result if x.nan?
32
+ return BigDecimal(x.infinite?) if x.infinite?
33
+ return BigDecimal(0) if x == 0
34
+ return -erf(-x, prec) if x < 0
35
+ return BigDecimal(1) if x > 5000000000 # erf(5000000000) > 1 - 1e-10000000000000000000
36
+ if x > 8
37
+ xf = x.to_f
38
+ log10_erfc = -xf ** 2 / Math.log(10) - Math.log10(xf * Math::PI ** 0.5)
39
+ erfc_prec = [prec + log10_erfc.ceil, 1].max
40
+ erfc = erfc_bit_burst(x, erfc_prec + BigDecimal::Internal::EXTRA_PREC)
41
+ return BigDecimal(1).sub(erfc, prec) if erfc
42
+ end
43
+
44
+ erf_bit_burst(x, prec + BigDecimal::Internal::EXTRA_PREC).mult(1, prec)
45
+ end
46
+
47
+ # Calculates erfc with given precision.
48
+ def self.erfc(x, prec)
49
+ prec = BigDecimal::Internal.coerce_validate_prec(prec, :erfc)
50
+ x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :erfc)
51
+ return BigDecimal::Internal.nan_computation_result if x.nan?
52
+ return BigDecimal(1 - x.infinite?) if x.infinite?
53
+ return BigDecimal(1).sub(erf(x, prec + BigDecimal::Internal::EXTRA_PREC), prec) if x < 0.5
54
+ return BigDecimal::Internal.underflow_computation_result if x > 5000000000 # erfc(5000000000) < 1e-10000000000000000000 (underflow)
55
+
56
+ if x > 8
57
+ y = erfc_bit_burst(x, prec + BigDecimal::Internal::EXTRA_PREC)
58
+ return y.mult(1, prec) if y
59
+ end
60
+
61
+ # erfc(x) = 1 - erf(x) < exp(-x**2)/x/sqrt(pi)
62
+ # Precision of erf(x) needs about log10(exp(-x**2)/x/sqrt(pi)) extra digits
63
+ log10 = 2.302585092994046
64
+ xf = x.to_f
65
+ high_prec = prec + BigDecimal::Internal::EXTRA_PREC + ((xf**2 + Math.log(xf) + Math.log(Math::PI)/2) / log10).ceil
66
+ BigDecimal(1).sub(erf_bit_burst(x, high_prec), prec)
67
+ end
68
+
69
+ # Matrix multiplication. m1 and m2 are size*size length array that represents size*size matrix
70
+ def self.matrix_mult(m1, m2, size, prec)
71
+ (size * size).times.map do |i|
72
+ size.times.map do |k|
73
+ m1[i / size * size + k].mult(m2[size * k + i % size], prec)
74
+ end.reduce {|a, b| a.add(b, prec) }
75
+ end
76
+ end
77
+
78
+ # Returns (erf(x + a) - erf(a)) * exp(a**2) * sqrt(pi) / 2 calculated with binary splitting method.
79
+ def self.erf_binary_splitting_diff(x, a, prec)
80
+ # Let f(x) = (erf(x + a) - erf(a)) * exp(a**2) * sqrt(pi) / 2
81
+ # f(x) satisfies the following differential equation:
82
+ # 2*(x+a)*f'(x) + f''(x) = 0
83
+ # We can derive the following recurrence for the Taylor coefficients of f:
84
+ # f(x) = x * (c0 + c1*x + c2*x**2 + c3*x**3 + ...)
85
+ # c(0) = 1
86
+ # c(1) = -a
87
+ # c(i) = -2 * (a * c(i - 1) + c(i - 2) * (i - 1) / i) / (i + 1)
88
+
89
+ # Estimate required number of terms by calculating c(i) with low precision
90
+ low_prec = 10
91
+ a_low = a.mult(1, low_prec)
92
+ x_low = x.mult(1, low_prec)
93
+ coefs = [BigDecimal(1), -a_low]
94
+ xn = BigDecimal(1)
95
+ threshold = BigDecimal(1)._decimal_shift(-prec)
96
+ steps = (2..).find do |n|
97
+ prevprev, prev = coefs
98
+ xn = xn.mult(x_low, low_prec)
99
+ coefs = prev, (a_low * prev + (prevprev * (n - 1)).div(n, low_prec)).mult(-2, low_prec).div(n + 1, low_prec)
100
+ coefs[0].mult(xn, low_prec).abs < threshold && coefs[1].mult(xn * x_low, low_prec).abs < threshold
101
+ end
102
+
103
+ # Let M(i) be a 2x2 matrix that generates the next coefficients vector (c(i-1), c(i))
104
+ # from the previous two coefficients (c(i-2), c(i-1)).
105
+ # M(i) = | 0, 1 |
106
+ # | -2*(i-1)/i/(i+1), -2*a/(i+1) |
107
+ #
108
+ # Then, we can calculate (c(steps-1), c(steps)) as M(steps)*M(steps-1)*...*M(2)*Vector(c0, c1).
109
+ #
110
+ # Calculate a matrix that represents the sum of the Taylor series:
111
+ # SumMatrix = ((((...+I)x*M4+I)*x*M3+I)*M2*x+I)
112
+ # Actual sum can be calculated as:
113
+ # SumMatrix * Vector(c0, c1) = Vector(c0+c1*x+c2*x**2+c3*x**3+..., _)
114
+ # In this binary splitting method, adjacent two operations are combined into one repeatedly.
115
+ # ((...) * x * A + B) / C is the form of each operation. A and B are 2x2 matrices, C is a scalar.
116
+
117
+ zero = BigDecimal(0)
118
+ operations = (2..steps + 2).map do |i|
119
+ d = BigDecimal(i * (i + 1))
120
+ [[zero, d, BigDecimal(-2 * (i - 1)), a * (-2 * i)], [d, zero, zero, d], d]
121
+ end
122
+
123
+ while operations.size > 1
124
+ xpow = xpow ? xpow.mult(xpow, prec) : x.mult(1, prec)
125
+ operations = operations.each_slice(2).map do |op1, op2|
126
+ # Combine two operations into one:
127
+ # (((Remaining * x * A2 + B2) / C2) * x * A1 + B1) / C1
128
+ # ((Remaining * (x*x) * (A2*A1) + (x*B2*A1+B1*C2)) / (C1*C2)
129
+ # Therefore, combined operation can be represented as:
130
+ # Anext = A2 * A1
131
+ # Bnext = x * B2 * A1 + B1 * C2
132
+ # Cnext = C1 * C2
133
+ # xnext = x * x
134
+ a1, b1, c1 = op1
135
+ a2, b2, c2 = op2 || [[zero] * 4, [zero] * 4, BigDecimal(1)]
136
+ [
137
+ matrix_mult(a2, a1, 2, prec),
138
+ array_weighted_sum(matrix_mult(b2, a1, 2, prec), xpow, b1, c2, prec),
139
+ c1.mult(c2, prec),
140
+ ]
141
+ end
142
+ end
143
+ _, sum_matrix, denominator = operations.first
144
+ sum = (sum_matrix[0] - a * sum_matrix[1]).div(denominator, prec)
145
+ x.mult(sum, prec)
146
+ end
147
+
148
+ # Calculates erfc(x) using bit-burst algorithm.
149
+ # Returns nil if the asymptotic expansion does not reach the requested precision.
150
+ def self.erfc_bit_burst(x, prec)
151
+ # By bounding the relative error via |d(erfc)/erfc| <= 2*x*|dx| (erfc(x) decays as exp(-x**2)/x),
152
+ # truncate x to the minimum digits sufficient for prec-digit accuracy of the result.
153
+ x = x.mult(1, prec + Math.log10(2 * x.to_f**2).ceil)
154
+ erf_erfc_bit_burst(x, prec, start_digits: 40, mode: :erfc)
155
+ end
156
+
157
+ # Calculates erf(x) using bit-burst algorithm.
158
+ def self.erf_bit_burst(x, prec)
159
+ # By bounding the error via erf'(x) = (2/sqrt(pi)) * exp(-x**2),
160
+ # truncate x to the minimum digits sufficient for prec-digit accuracy of the result.
161
+ x = x.mult(1, [(prec - x.floor**2 / Math.log(10) + Math.log10(x.ceil)).ceil, 10].max)
162
+ erf_erfc_bit_burst(x, prec, start_digits: 8, mode: :erf)
163
+ end
164
+
165
+ # Calculates erf or erfc using bit-burst algorithm.
166
+ # Returns nil if erfc mode cannot reach the requested precision.
167
+ def self.erf_erfc_bit_burst(x, prec, start_digits:, mode:)
168
+ digits = [-x.exponent * 2, start_digits].max
169
+ partial = x.truncate(digits)
170
+ case mode
171
+ when :erf
172
+ f = erf_exp2_binary_splitting(partial, prec)
173
+ when :erfc
174
+ f = erfc_exp2_asymptotic_binary_splitting(partial, prec)
175
+ return unless f
176
+ end
177
+
178
+ exp_scale = BigMath.exp(-partial * partial, prec)
179
+ f = f.mult(exp_scale, prec)
180
+
181
+ calculated_x = partial
182
+ x -= partial
183
+
184
+ until x.zero?
185
+ digits *= 2
186
+ partial = x.truncate(digits)
187
+ next if partial.zero?
188
+
189
+ diff_prec = [prec - f.exponent + exp_scale.exponent + partial.exponent, 1].max
190
+ diff = erf_binary_splitting_diff(partial, calculated_x, diff_prec)
191
+ case mode
192
+ when :erf
193
+ f = f.add(diff.mult(exp_scale, prec), prec)
194
+ when :erfc
195
+ f = f.sub(diff.mult(exp_scale, prec), prec)
196
+ end
197
+
198
+ calculated_x += partial
199
+ x -= partial
200
+ exp_scale = exp_scale.mult(BigMath.exp(partial * (partial - 2 * calculated_x), diff_prec), diff_prec) unless x.zero?
201
+ end
202
+ f.mult(BigDecimal(2).div(BigMath::PI(prec).sqrt(prec), prec), prec)
203
+ end
204
+
205
+ # Matrix/Vector weighted sum
206
+ def self.array_weighted_sum(m1, w1, m2, w2, prec)
207
+ m1.zip(m2).map {|v1, v2| (v1 * w1).add(v2 * w2, prec) }
208
+ end
209
+
210
+ # Calculates Taylor expansion of erf(x)*exp(x**2)*sqrt(pi)/2 with binary splitting method.
211
+ def self.erf_exp2_binary_splitting(x, prec)
212
+ # Let f(x) = erf(x)*exp(x**2)*sqrt(pi)/2
213
+ # = c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + ...
214
+ # f(x) is designed to make all coefficients positive so that we don't need to consider cancellation error.
215
+ #
216
+ # f(x) satisfies the following differential equation:
217
+ # f'(x) = 1 + 2 * x * f(x)
218
+ # f'(x) = c1 + 2*c2*x + 3*c3*x**2 + 4*c4*x**3 + 5*c5*x**4 + ...
219
+ # = 1+2*x*(c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + ...)
220
+ # therefore,
221
+ # c0 = 0
222
+ # c1 = 1
223
+ # c2 = 2 * (c0 + c1) / 2
224
+ # c3 = 2 * (c1 + c2) / 3
225
+ # c4 = 2 * (c2 + c3) / 4
226
+
227
+ # Find the smallest n where the n-th Taylor term |c_n * x^n| falls below the precision
228
+ # threshold, using a Stirling-based upper bound on |c_n|.
229
+ log10f = Math.log(10)
230
+ cexponent = Math.log10(Math.sqrt(2)) + BigDecimal::Internal.float_log(x.abs) / log10f
231
+
232
+ x_to_f = x < 1e-300 ? 1e-300 : x.to_f # x.to_f may underflow when x is very small (e.g. 1e-400)
233
+ steps = (2..).bsearch do |n|
234
+ x_to_f ** 2 < n && n * cexponent + Math.lgamma(n / 2)[0] / log10f + n * Math.log10(2) - Math.lgamma(n - 1)[0] / log10f < -prec + x_to_f**2 / log10f
235
+ end
236
+
237
+ denominators = (steps / 2).times.map {|i| 2 * i + 3 }
238
+ x.mult(1 + BigDecimal::Internal.taylor_sum_binary_splitting(2 * x * x, denominators, prec), prec)
239
+ end
240
+
241
+ # Calculates asymptotic expansion of erfc(x)*exp(x**2)*sqrt(pi)/2 with binary splitting method
242
+ def self.erfc_exp2_asymptotic_binary_splitting(x, prec)
243
+ # Let f(x) = erfc(x)*sqrt(pi)*exp(x**2)/2
244
+ # f(x) satisfies the following differential equation:
245
+ # 2*x*f(x) = f'(x) + 1
246
+ # From the above equation, we can derive the following asymptotic expansion:
247
+ # f(x) = (0..kmax).sum { (-1)**k * (2*k)! / 4**k / k! / x**(2*k) } / x / 2
248
+
249
+ # This asymptotic expansion does not converge.
250
+ # But if there is a k that satisfies (2*k)! / 4**k / k! / x**(2*k) < 10**(-prec),
251
+ # It is enough to calculate erfc within the given precision.
252
+ # Using Stirling's approximation, we can simplify this condition to:
253
+ # log(2)/2 + k*log(k) - k - 2*k*log(x) < -prec*log(10)
254
+ # and the left side is minimized when k = x**2.
255
+ xf = x.to_f
256
+ kmax = (1..(xf ** 2).floor).bsearch do |k|
257
+ Math.log(2) / 2 + k * Math.log(k) - k - 2 * k * Math.log(xf) < -prec * Math.log(10)
258
+ end
259
+ return unless kmax
260
+
261
+ # Convert asymptotic expansion to nested form:
262
+ # 1 + a/x + a*b/x/x + a*b*c/x/x/x + a*b*c/x/x/x*rest
263
+ # = 1 + (a/x) * (1 + (b/x) * (1 + (c/x) * (1 + rest)))
264
+ #
265
+ # And calculate it with binary splitting:
266
+ # (a1/d + b1/d * (a2/d + b2/d * (rest)))
267
+ # = ((a1*d+b1*a2)/(d*d) + b1*b2/(d*denominator) * (rest)))
268
+ denominator = x.mult(x, prec).mult(2, prec)
269
+ fractions = (1..kmax).map do |k|
270
+ [denominator, BigDecimal(1 - 2 * k)]
271
+ end
272
+ while fractions.size > 1
273
+ fractions = fractions.each_slice(2).map do |fraction1, fraction2|
274
+ a1, b1 = fraction1
275
+ a2, b2 = fraction2 || [BigDecimal(0), denominator]
276
+ [
277
+ a1.mult(denominator, prec).add(b1.mult(a2, prec), prec),
278
+ b1.mult(b2, prec),
279
+ ]
280
+ end
281
+ denominator = denominator.mult(denominator, prec)
282
+ end
283
+ # Plug rest = 1 into the merged form: the innermost "(1 + rest)" of the nested expansion
284
+ # evaluates to 1 at truncation (rest = 0).
285
+ sum = fractions[0][0].add(fractions[0][1], prec).div(denominator, prec)
286
+ sum.div(x, prec) / 2
287
+ end
288
+ end
289
+
290
+ private_constant :Erf
291
+ end