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.
- checksums.yaml +4 -4
- data/bigdecimal.gemspec +8 -1
- data/ext/bigdecimal/bigdecimal.c +288 -303
- data/ext/bigdecimal/bigdecimal.h +48 -42
- data/ext/bigdecimal/div.h +219 -0
- data/ext/bigdecimal/extconf.rb +5 -2
- data/ext/bigdecimal/missing/dtoa.c +184 -137
- data/ext/bigdecimal/missing.h +4 -2
- data/ext/bigdecimal/ntt.h +191 -0
- data/lib/bigdecimal/jacobian.rb +2 -0
- data/lib/bigdecimal/ludcmp.rb +2 -0
- data/lib/bigdecimal/math/erf.rb +291 -0
- data/lib/bigdecimal/math/gamma.rb +513 -0
- data/lib/bigdecimal/math.rb +548 -81
- data/lib/bigdecimal/newton.rb +2 -0
- data/lib/bigdecimal/util.rb +1 -1
- data/lib/bigdecimal.rb +121 -73
- data/sample/linear.rb +73 -37
- data/sample/nlsolve.rb +47 -30
- data/sample/pi.rb +2 -7
- data/sig/big_decimal.rbs +1504 -0
- data/sig/big_decimal_util.rbs +158 -0
- data/sig/big_math.rbs +423 -0
- metadata +10 -3
data/ext/bigdecimal/missing.h
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
+
}
|
data/lib/bigdecimal/jacobian.rb
CHANGED
data/lib/bigdecimal/ludcmp.rb
CHANGED
|
@@ -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
|