bigdecimal 4.1.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.
data/ext/bigdecimal/ntt.h CHANGED
@@ -68,7 +68,7 @@ ntt(int size_bits, uint32_t *input, uint32_t *output, uint32_t *tmp, int r_base,
68
68
 
69
69
  // rmax**(1 << shift) % prime == 1
70
70
  // r**size % prime == 1
71
- uint32_t rmax = mod_pow(r_base, base, prime);
71
+ uint32_t rmax = mod_pow((uint32_t)r_base, (uint32_t)base, prime);
72
72
  uint32_t r = mod_pow(rmax, (uint32_t)1 << (shift - size_bits), prime);
73
73
 
74
74
  if (dir < 0) r = mod_pow(r, prime - 2, prime);
@@ -123,7 +123,7 @@ ntt_multiply(size_t a_size, size_t b_size, uint32_t *a, uint32_t *b, uint32_t *c
123
123
  return;
124
124
  }
125
125
 
126
- int ntt_size_bits = bit_length(b_size - 1) + 1;
126
+ int ntt_size_bits = (int)bit_length(b_size - 1) + 1;
127
127
  if (ntt_size_bits > MAX_NTT32_BITS) {
128
128
  rb_raise(rb_eArgError, "Multiply size too large");
129
129
  }
@@ -133,7 +133,7 @@ ntt_multiply(size_t a_size, size_t b_size, uint32_t *a, uint32_t *b, uint32_t *c
133
133
  uint32_t batch_size = ntt_size - (uint32_t)b_size;
134
134
  uint32_t batch_count = (uint32_t)((a_size + batch_size - 1) / batch_size);
135
135
 
136
- uint32_t *mem = ruby_xcalloc(sizeof(uint32_t), ntt_size * 9);
136
+ uint32_t *mem = ruby_xcalloc(ntt_size * 9, sizeof(uint32_t));
137
137
  uint32_t *ntt1 = mem;
138
138
  uint32_t *ntt2 = mem + ntt_size;
139
139
  uint32_t *ntt3 = mem + ntt_size * 2;
@@ -177,12 +177,12 @@ ntt_multiply(size_t a_size, size_t b_size, uint32_t *a, uint32_t *b, uint32_t *c
177
177
  // so this sum doesn't overflow uint32_t.
178
178
  for (int j = 0; j < 3; j++) {
179
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 - j] += dig[j];
180
+ if (dig[j]) c[idx * batch_size + i + 1 - (uint32_t)j] += dig[j];
181
181
  }
182
182
  }
183
183
  }
184
184
  uint32_t carry = 0;
185
- for (int32_t i = (uint32_t)(a_size + b_size - 1); i >= 0; i--) {
185
+ for (int32_t i = (int32_t)(a_size + b_size - 1); i >= 0; i--) {
186
186
  uint32_t v = c[i] + carry;
187
187
  c[i] = v % NTT_DECDIG_BASE;
188
188
  carry = v / NTT_DECDIG_BASE;
@@ -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