bigdecimal 3.3.0-java → 4.0.0-java
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/lib/bigdecimal/jacobian.rb +2 -0
- data/lib/bigdecimal/ludcmp.rb +2 -0
- data/lib/bigdecimal/math.rb +710 -10
- data/lib/bigdecimal/newton.rb +2 -0
- data/lib/bigdecimal.rb +38 -23
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad9e6c7afd5498f48f113f3fe85a358e6835b7ee0f1fda8cddde4b444235f7a1
|
|
4
|
+
data.tar.gz: 03fdbff47e6b17562f97c44d6077fd1792f63d848e540bf87d5132b6707e5f1a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 300ab42cf0600c53435985be7945a1908fe370b7d651bd2a8dbc6e639a12da1425c914bd3375fcab3f261dc64ffbbdd0500095c638b3987688537e383c4d7f95
|
|
7
|
+
data.tar.gz: 7b84d5497f9d3edc1a5168592ff5d280dc428ca3851f98d9af0bd0d9e5a8beff619c5ac9a8f6eebabd542a44069c37c92d11a35e21b6b7a9a27cb4bd70bc7f19
|
data/lib/bigdecimal/jacobian.rb
CHANGED
data/lib/bigdecimal/ludcmp.rb
CHANGED
data/lib/bigdecimal/math.rb
CHANGED
|
@@ -5,15 +5,36 @@ require 'bigdecimal'
|
|
|
5
5
|
#--
|
|
6
6
|
# Contents:
|
|
7
7
|
# sqrt(x, prec)
|
|
8
|
+
# cbrt(x, prec)
|
|
9
|
+
# hypot(x, y, prec)
|
|
8
10
|
# sin (x, prec)
|
|
9
11
|
# cos (x, prec)
|
|
10
12
|
# tan (x, prec)
|
|
13
|
+
# asin(x, prec)
|
|
14
|
+
# acos(x, prec)
|
|
11
15
|
# atan(x, prec)
|
|
16
|
+
# atan2(y, x, prec)
|
|
17
|
+
# sinh (x, prec)
|
|
18
|
+
# cosh (x, prec)
|
|
19
|
+
# tanh (x, prec)
|
|
20
|
+
# asinh(x, prec)
|
|
21
|
+
# acosh(x, prec)
|
|
22
|
+
# atanh(x, prec)
|
|
23
|
+
# log2 (x, prec)
|
|
24
|
+
# log10(x, prec)
|
|
25
|
+
# log1p(x, prec)
|
|
26
|
+
# expm1(x, prec)
|
|
27
|
+
# erf (x, prec)
|
|
28
|
+
# erfc(x, prec)
|
|
29
|
+
# gamma(x, prec)
|
|
30
|
+
# lgamma(x, prec)
|
|
31
|
+
# frexp(x)
|
|
32
|
+
# ldexp(x, exponent)
|
|
12
33
|
# PI (prec)
|
|
13
34
|
# E (prec) == exp(1.0,prec)
|
|
14
35
|
#
|
|
15
36
|
# where:
|
|
16
|
-
# x
|
|
37
|
+
# x, y ... BigDecimal number to be computed.
|
|
17
38
|
# prec ... Number of digits to be obtained.
|
|
18
39
|
#++
|
|
19
40
|
#
|
|
@@ -41,7 +62,7 @@ module BigMath
|
|
|
41
62
|
# #=> "0.14142135623730950488016887242097e1"
|
|
42
63
|
#
|
|
43
64
|
def sqrt(x, prec)
|
|
44
|
-
BigDecimal::Internal.
|
|
65
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :sqrt)
|
|
45
66
|
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :sqrt)
|
|
46
67
|
x.sqrt(prec)
|
|
47
68
|
end
|
|
@@ -73,6 +94,53 @@ module BigMath
|
|
|
73
94
|
end
|
|
74
95
|
end
|
|
75
96
|
|
|
97
|
+
# call-seq:
|
|
98
|
+
# cbrt(decimal, numeric) -> BigDecimal
|
|
99
|
+
#
|
|
100
|
+
# Computes the cube root of +decimal+ to the specified number of digits of
|
|
101
|
+
# precision, +numeric+.
|
|
102
|
+
#
|
|
103
|
+
# BigMath.cbrt(BigDecimal('2'), 32).to_s
|
|
104
|
+
# #=> "0.12599210498948731647672106072782e1"
|
|
105
|
+
#
|
|
106
|
+
def cbrt(x, prec)
|
|
107
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :cbrt)
|
|
108
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :cbrt)
|
|
109
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
110
|
+
return BigDecimal::Internal.infinity_computation_result * x.infinite? if x.infinite?
|
|
111
|
+
return BigDecimal(0) if x.zero?
|
|
112
|
+
|
|
113
|
+
x = -x if neg = x < 0
|
|
114
|
+
ex = x.exponent / 3
|
|
115
|
+
x = x._decimal_shift(-3 * ex)
|
|
116
|
+
y = BigDecimal(Math.cbrt(x.to_f), 0)
|
|
117
|
+
precs = [prec + BigDecimal.double_fig]
|
|
118
|
+
precs << 2 + precs.last / 2 while precs.last > BigDecimal.double_fig
|
|
119
|
+
precs.reverse_each do |p|
|
|
120
|
+
y = (2 * y + x.div(y, p).div(y, p)).div(3, p)
|
|
121
|
+
end
|
|
122
|
+
y._decimal_shift(ex).mult(neg ? -1 : 1, prec)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# call-seq:
|
|
126
|
+
# hypot(x, y, numeric) -> BigDecimal
|
|
127
|
+
#
|
|
128
|
+
# Returns sqrt(x**2 + y**2) to the specified number of digits of
|
|
129
|
+
# precision, +numeric+.
|
|
130
|
+
#
|
|
131
|
+
# BigMath.hypot(BigDecimal('1'), BigDecimal('2'), 32).to_s
|
|
132
|
+
# #=> "0.22360679774997896964091736687313e1"
|
|
133
|
+
#
|
|
134
|
+
def hypot(x, y, prec)
|
|
135
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :hypot)
|
|
136
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :hypot)
|
|
137
|
+
y = BigDecimal::Internal.coerce_to_bigdecimal(y, prec, :hypot)
|
|
138
|
+
return BigDecimal::Internal.nan_computation_result if x.nan? || y.nan?
|
|
139
|
+
return BigDecimal::Internal.infinity_computation_result if x.infinite? || y.infinite?
|
|
140
|
+
prec2 = prec + BigDecimal.double_fig
|
|
141
|
+
sqrt(x.mult(x, prec2) + y.mult(y, prec2), prec)
|
|
142
|
+
end
|
|
143
|
+
|
|
76
144
|
# call-seq:
|
|
77
145
|
# sin(decimal, numeric) -> BigDecimal
|
|
78
146
|
#
|
|
@@ -85,7 +153,7 @@ module BigMath
|
|
|
85
153
|
# #=> "0.70710807985947359435812921837984e0"
|
|
86
154
|
#
|
|
87
155
|
def sin(x, prec)
|
|
88
|
-
BigDecimal::Internal.
|
|
156
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :sin)
|
|
89
157
|
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :sin)
|
|
90
158
|
return BigDecimal::Internal.nan_computation_result if x.infinite? || x.nan?
|
|
91
159
|
n = prec + BigDecimal.double_fig
|
|
@@ -122,7 +190,7 @@ module BigMath
|
|
|
122
190
|
# #=> "-0.99999999999999999999999999999997e0"
|
|
123
191
|
#
|
|
124
192
|
def cos(x, prec)
|
|
125
|
-
BigDecimal::Internal.
|
|
193
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :cos)
|
|
126
194
|
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :cos)
|
|
127
195
|
return BigDecimal::Internal.nan_computation_result if x.infinite? || x.nan?
|
|
128
196
|
sign, x = _sin_periodic_reduction(x, prec + BigDecimal.double_fig, add_half_pi: true)
|
|
@@ -144,10 +212,61 @@ module BigMath
|
|
|
144
212
|
# #=> "0.99999999999999999999999830836025e0"
|
|
145
213
|
#
|
|
146
214
|
def tan(x, prec)
|
|
147
|
-
BigDecimal::Internal.
|
|
215
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :tan)
|
|
148
216
|
sin(x, prec + BigDecimal.double_fig).div(cos(x, prec + BigDecimal.double_fig), prec)
|
|
149
217
|
end
|
|
150
218
|
|
|
219
|
+
# call-seq:
|
|
220
|
+
# asin(decimal, numeric) -> BigDecimal
|
|
221
|
+
#
|
|
222
|
+
# Computes the arcsine of +decimal+ to the specified number of digits of
|
|
223
|
+
# precision, +numeric+.
|
|
224
|
+
#
|
|
225
|
+
# If +decimal+ is NaN, returns NaN.
|
|
226
|
+
#
|
|
227
|
+
# BigMath.asin(BigDecimal('0.5'), 32).to_s
|
|
228
|
+
# #=> "0.52359877559829887307710723054658e0"
|
|
229
|
+
#
|
|
230
|
+
def asin(x, prec)
|
|
231
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :asin)
|
|
232
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :asin)
|
|
233
|
+
raise Math::DomainError, "Out of domain argument for asin" if x < -1 || x > 1
|
|
234
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
235
|
+
|
|
236
|
+
prec2 = prec + BigDecimal.double_fig
|
|
237
|
+
cos = (1 - x**2).sqrt(prec2)
|
|
238
|
+
if cos.zero?
|
|
239
|
+
PI(prec2).div(x > 0 ? 2 : -2, prec)
|
|
240
|
+
else
|
|
241
|
+
atan(x.div(cos, prec2), prec)
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# call-seq:
|
|
246
|
+
# acos(decimal, numeric) -> BigDecimal
|
|
247
|
+
#
|
|
248
|
+
# Computes the arccosine of +decimal+ to the specified number of digits of
|
|
249
|
+
# precision, +numeric+.
|
|
250
|
+
#
|
|
251
|
+
# If +decimal+ is NaN, returns NaN.
|
|
252
|
+
#
|
|
253
|
+
# BigMath.acos(BigDecimal('0.5'), 32).to_s
|
|
254
|
+
# #=> "0.10471975511965977461542144610932e1"
|
|
255
|
+
#
|
|
256
|
+
def acos(x, prec)
|
|
257
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :acos)
|
|
258
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :acos)
|
|
259
|
+
raise Math::DomainError, "Out of domain argument for acos" if x < -1 || x > 1
|
|
260
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
261
|
+
|
|
262
|
+
prec2 = prec + BigDecimal.double_fig
|
|
263
|
+
return (PI(prec2) / 2).sub(asin(x, prec2), prec) if x < 0
|
|
264
|
+
return PI(prec2).div(2, prec) if x.zero?
|
|
265
|
+
|
|
266
|
+
sin = (1 - x**2).sqrt(prec2)
|
|
267
|
+
atan(sin.div(x, prec2), prec)
|
|
268
|
+
end
|
|
269
|
+
|
|
151
270
|
# call-seq:
|
|
152
271
|
# atan(decimal, numeric) -> BigDecimal
|
|
153
272
|
#
|
|
@@ -160,14 +279,14 @@ module BigMath
|
|
|
160
279
|
# #=> "-0.78539816339744830961566084581988e0"
|
|
161
280
|
#
|
|
162
281
|
def atan(x, prec)
|
|
163
|
-
BigDecimal::Internal.
|
|
282
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :atan)
|
|
164
283
|
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :atan)
|
|
165
284
|
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
166
285
|
n = prec + BigDecimal.double_fig
|
|
167
286
|
pi = PI(n)
|
|
168
287
|
x = -x if neg = x < 0
|
|
169
288
|
return pi.div(neg ? -2 : 2, prec) if x.infinite?
|
|
170
|
-
return pi.div(neg ? -4 : 4, prec) if x.round(
|
|
289
|
+
return pi.div(neg ? -4 : 4, prec) if x.round(n) == 1
|
|
171
290
|
x = BigDecimal("1").div(x, n) if inv = x > 1
|
|
172
291
|
x = (-1 + sqrt(1 + x.mult(x, n), n)).div(x, n) if dbl = x > 0.5
|
|
173
292
|
y = x
|
|
@@ -188,6 +307,587 @@ module BigMath
|
|
|
188
307
|
y.mult(1, prec)
|
|
189
308
|
end
|
|
190
309
|
|
|
310
|
+
# call-seq:
|
|
311
|
+
# atan2(decimal, decimal, numeric) -> BigDecimal
|
|
312
|
+
#
|
|
313
|
+
# Computes the arctangent of y and x to the specified number of digits of
|
|
314
|
+
# precision, +numeric+.
|
|
315
|
+
#
|
|
316
|
+
# BigMath.atan2(BigDecimal('-1'), BigDecimal('1'), 32).to_s
|
|
317
|
+
# #=> "-0.78539816339744830961566084581988e0"
|
|
318
|
+
#
|
|
319
|
+
def atan2(y, x, prec)
|
|
320
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :atan2)
|
|
321
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :atan2)
|
|
322
|
+
y = BigDecimal::Internal.coerce_to_bigdecimal(y, prec, :atan2)
|
|
323
|
+
return BigDecimal::Internal.nan_computation_result if x.nan? || y.nan?
|
|
324
|
+
|
|
325
|
+
if x.infinite? || y.infinite?
|
|
326
|
+
one = BigDecimal(1)
|
|
327
|
+
zero = BigDecimal(0)
|
|
328
|
+
x = x.infinite? ? (x > 0 ? one : -one) : zero
|
|
329
|
+
y = y.infinite? ? (y > 0 ? one : -one) : y.sign * zero
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
return x.sign >= 0 ? BigDecimal(0) : y.sign * PI(prec) if y.zero?
|
|
333
|
+
|
|
334
|
+
y = -y if neg = y < 0
|
|
335
|
+
xlarge = y.abs < x.abs
|
|
336
|
+
prec2 = prec + BigDecimal.double_fig
|
|
337
|
+
if x > 0
|
|
338
|
+
v = xlarge ? atan(y.div(x, prec2), prec) : PI(prec2) / 2 - atan(x.div(y, prec2), prec2)
|
|
339
|
+
else
|
|
340
|
+
v = xlarge ? PI(prec2) - atan(-y.div(x, prec2), prec2) : PI(prec2) / 2 + atan(x.div(-y, prec2), prec2)
|
|
341
|
+
end
|
|
342
|
+
v.mult(neg ? -1 : 1, prec)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# call-seq:
|
|
346
|
+
# sinh(decimal, numeric) -> BigDecimal
|
|
347
|
+
#
|
|
348
|
+
# Computes the hyperbolic sine of +decimal+ to the specified number of digits of
|
|
349
|
+
# precision, +numeric+.
|
|
350
|
+
#
|
|
351
|
+
# If +decimal+ is NaN, returns NaN.
|
|
352
|
+
#
|
|
353
|
+
# BigMath.sinh(BigDecimal('1'), 32).to_s
|
|
354
|
+
# #=> "0.11752011936438014568823818505956e1"
|
|
355
|
+
#
|
|
356
|
+
def sinh(x, prec)
|
|
357
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :sinh)
|
|
358
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :sinh)
|
|
359
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
360
|
+
return BigDecimal::Internal.infinity_computation_result * x.infinite? if x.infinite?
|
|
361
|
+
|
|
362
|
+
prec2 = prec + BigDecimal.double_fig
|
|
363
|
+
prec2 -= x.exponent if x.exponent < 0
|
|
364
|
+
e = exp(x, prec2)
|
|
365
|
+
(e - BigDecimal(1).div(e, prec2)).div(2, prec)
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# call-seq:
|
|
369
|
+
# cosh(decimal, numeric) -> BigDecimal
|
|
370
|
+
#
|
|
371
|
+
# Computes the hyperbolic cosine of +decimal+ to the specified number of digits of
|
|
372
|
+
# precision, +numeric+.
|
|
373
|
+
#
|
|
374
|
+
# If +decimal+ is NaN, returns NaN.
|
|
375
|
+
#
|
|
376
|
+
# BigMath.cosh(BigDecimal('1'), 32).to_s
|
|
377
|
+
# #=> "0.15430806348152437784779056207571e1"
|
|
378
|
+
#
|
|
379
|
+
def cosh(x, prec)
|
|
380
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :cosh)
|
|
381
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :cosh)
|
|
382
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
383
|
+
return BigDecimal::Internal.infinity_computation_result if x.infinite?
|
|
384
|
+
|
|
385
|
+
prec2 = prec + BigDecimal.double_fig
|
|
386
|
+
e = exp(x, prec2)
|
|
387
|
+
(e + BigDecimal(1).div(e, prec2)).div(2, prec)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
# call-seq:
|
|
391
|
+
# tanh(decimal, numeric) -> BigDecimal
|
|
392
|
+
#
|
|
393
|
+
# Computes the hyperbolic tangent of +decimal+ to the specified number of digits of
|
|
394
|
+
# precision, +numeric+.
|
|
395
|
+
#
|
|
396
|
+
# If +decimal+ is NaN, returns NaN.
|
|
397
|
+
#
|
|
398
|
+
# BigMath.tanh(BigDecimal('1'), 32).to_s
|
|
399
|
+
# #=> "0.76159415595576488811945828260479e0"
|
|
400
|
+
#
|
|
401
|
+
def tanh(x, prec)
|
|
402
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :tanh)
|
|
403
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :tanh)
|
|
404
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
405
|
+
return BigDecimal(x.infinite?) if x.infinite?
|
|
406
|
+
|
|
407
|
+
prec2 = prec + BigDecimal.double_fig + [-x.exponent, 0].max
|
|
408
|
+
e = exp(x, prec2)
|
|
409
|
+
einv = BigDecimal(1).div(e, prec2)
|
|
410
|
+
(e - einv).div(e + einv, prec)
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# call-seq:
|
|
414
|
+
# asinh(decimal, numeric) -> BigDecimal
|
|
415
|
+
#
|
|
416
|
+
# Computes the inverse hyperbolic sine of +decimal+ to the specified number of digits of
|
|
417
|
+
# precision, +numeric+.
|
|
418
|
+
#
|
|
419
|
+
# If +decimal+ is NaN, returns NaN.
|
|
420
|
+
#
|
|
421
|
+
# BigMath.asinh(BigDecimal('1'), 32).to_s
|
|
422
|
+
# #=> "0.88137358701954302523260932497979e0"
|
|
423
|
+
#
|
|
424
|
+
def asinh(x, prec)
|
|
425
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :asinh)
|
|
426
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :asinh)
|
|
427
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
428
|
+
return BigDecimal::Internal.infinity_computation_result * x.infinite? if x.infinite?
|
|
429
|
+
return -asinh(-x, prec) if x < 0
|
|
430
|
+
|
|
431
|
+
sqrt_prec = prec + [-x.exponent, 0].max + BigDecimal.double_fig
|
|
432
|
+
log(x + sqrt(x**2 + 1, sqrt_prec), prec)
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
# call-seq:
|
|
436
|
+
# acosh(decimal, numeric) -> BigDecimal
|
|
437
|
+
#
|
|
438
|
+
# Computes the inverse hyperbolic cosine of +decimal+ to the specified number of digits of
|
|
439
|
+
# precision, +numeric+.
|
|
440
|
+
#
|
|
441
|
+
# If +decimal+ is NaN, returns NaN.
|
|
442
|
+
#
|
|
443
|
+
# BigMath.acosh(BigDecimal('2'), 32).to_s
|
|
444
|
+
# #=> "0.1316957896924816708625046347308e1"
|
|
445
|
+
#
|
|
446
|
+
def acosh(x, prec)
|
|
447
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :acosh)
|
|
448
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :acosh)
|
|
449
|
+
raise Math::DomainError, "Out of domain argument for acosh" if x < 1
|
|
450
|
+
return BigDecimal::Internal.infinity_computation_result if x.infinite?
|
|
451
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
452
|
+
|
|
453
|
+
log(x + sqrt(x**2 - 1, prec + BigDecimal.double_fig), prec)
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# call-seq:
|
|
457
|
+
# atanh(decimal, numeric) -> BigDecimal
|
|
458
|
+
#
|
|
459
|
+
# Computes the inverse hyperbolic tangent of +decimal+ to the specified number of digits of
|
|
460
|
+
# precision, +numeric+.
|
|
461
|
+
#
|
|
462
|
+
# If +decimal+ is NaN, returns NaN.
|
|
463
|
+
#
|
|
464
|
+
# BigMath.atanh(BigDecimal('0.5'), 32).to_s
|
|
465
|
+
# #=> "0.54930614433405484569762261846126e0"
|
|
466
|
+
#
|
|
467
|
+
def atanh(x, prec)
|
|
468
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :atanh)
|
|
469
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :atanh)
|
|
470
|
+
raise Math::DomainError, "Out of domain argument for atanh" if x < -1 || x > 1
|
|
471
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
472
|
+
return BigDecimal::Internal.infinity_computation_result if x == 1
|
|
473
|
+
return -BigDecimal::Internal.infinity_computation_result if x == -1
|
|
474
|
+
|
|
475
|
+
prec2 = prec + BigDecimal.double_fig
|
|
476
|
+
(log(x + 1, prec2) - log(1 - x, prec2)).div(2, prec)
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
# call-seq:
|
|
480
|
+
# BigMath.log2(decimal, numeric) -> BigDecimal
|
|
481
|
+
#
|
|
482
|
+
# Computes the base 2 logarithm of +decimal+ to the specified number of
|
|
483
|
+
# digits of precision, +numeric+.
|
|
484
|
+
#
|
|
485
|
+
# If +decimal+ is zero or negative, raises Math::DomainError.
|
|
486
|
+
#
|
|
487
|
+
# If +decimal+ is positive infinity, returns Infinity.
|
|
488
|
+
#
|
|
489
|
+
# If +decimal+ is NaN, returns NaN.
|
|
490
|
+
#
|
|
491
|
+
# BigMath.log2(BigDecimal('3'), 32).to_s
|
|
492
|
+
# #=> "0.15849625007211561814537389439478e1"
|
|
493
|
+
#
|
|
494
|
+
def log2(x, prec)
|
|
495
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :log2)
|
|
496
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :log2)
|
|
497
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
498
|
+
return BigDecimal::Internal.infinity_computation_result if x.infinite? == 1
|
|
499
|
+
|
|
500
|
+
prec2 = prec + BigDecimal.double_fig * 3 / 2
|
|
501
|
+
v = log(x, prec2).div(log(BigDecimal(2), prec2), prec2)
|
|
502
|
+
# Perform half-up rounding to calculate log2(2**n)==n correctly in every rounding mode
|
|
503
|
+
v = v.round(prec + BigDecimal.double_fig - (v.exponent < 0 ? v.exponent : 0), BigDecimal::ROUND_HALF_UP)
|
|
504
|
+
v.mult(1, prec)
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
# call-seq:
|
|
508
|
+
# BigMath.log10(decimal, numeric) -> BigDecimal
|
|
509
|
+
#
|
|
510
|
+
# Computes the base 10 logarithm of +decimal+ to the specified number of
|
|
511
|
+
# digits of precision, +numeric+.
|
|
512
|
+
#
|
|
513
|
+
# If +decimal+ is zero or negative, raises Math::DomainError.
|
|
514
|
+
#
|
|
515
|
+
# If +decimal+ is positive infinity, returns Infinity.
|
|
516
|
+
#
|
|
517
|
+
# If +decimal+ is NaN, returns NaN.
|
|
518
|
+
#
|
|
519
|
+
# BigMath.log10(BigDecimal('3'), 32).to_s
|
|
520
|
+
# #=> "0.47712125471966243729502790325512e0"
|
|
521
|
+
#
|
|
522
|
+
def log10(x, prec)
|
|
523
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :log10)
|
|
524
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :log10)
|
|
525
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
526
|
+
return BigDecimal::Internal.infinity_computation_result if x.infinite? == 1
|
|
527
|
+
|
|
528
|
+
prec2 = prec + BigDecimal.double_fig * 3 / 2
|
|
529
|
+
v = log(x, prec2).div(log(BigDecimal(10), prec2), prec2)
|
|
530
|
+
# Perform half-up rounding to calculate log10(10**n)==n correctly in every rounding mode
|
|
531
|
+
v = v.round(prec + BigDecimal.double_fig - (v.exponent < 0 ? v.exponent : 0), BigDecimal::ROUND_HALF_UP)
|
|
532
|
+
v.mult(1, prec)
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
# call-seq:
|
|
536
|
+
# BigMath.log1p(decimal, numeric) -> BigDecimal
|
|
537
|
+
#
|
|
538
|
+
# Computes log(1 + decimal) to the specified number of digits of precision, +numeric+.
|
|
539
|
+
#
|
|
540
|
+
# BigMath.log1p(BigDecimal('0.1'), 32).to_s
|
|
541
|
+
# #=> "0.95310179804324860043952123280765e-1"
|
|
542
|
+
#
|
|
543
|
+
def log1p(x, prec)
|
|
544
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :log1p)
|
|
545
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :log1p)
|
|
546
|
+
raise Math::DomainError, 'Out of domain argument for log1p' if x < -1
|
|
547
|
+
|
|
548
|
+
return log(x + 1, prec)
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
# call-seq:
|
|
552
|
+
# BigMath.expm1(decimal, numeric) -> BigDecimal
|
|
553
|
+
#
|
|
554
|
+
# Computes exp(decimal) - 1 to the specified number of digits of precision, +numeric+.
|
|
555
|
+
#
|
|
556
|
+
# BigMath.expm1(BigDecimal('0.1'), 32).to_s
|
|
557
|
+
# #=> "0.10517091807564762481170782649025e0"
|
|
558
|
+
#
|
|
559
|
+
def expm1(x, prec)
|
|
560
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :expm1)
|
|
561
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :expm1)
|
|
562
|
+
return BigDecimal(-1) if x.infinite? == -1
|
|
563
|
+
|
|
564
|
+
exp_prec = prec
|
|
565
|
+
if x < -1
|
|
566
|
+
# log10(exp(x)) = x * log10(e)
|
|
567
|
+
lg_e = 0.4342944819032518
|
|
568
|
+
exp_prec = prec + (lg_e * x).ceil + BigDecimal.double_fig
|
|
569
|
+
elsif x < 1
|
|
570
|
+
exp_prec = prec - x.exponent + BigDecimal.double_fig
|
|
571
|
+
else
|
|
572
|
+
exp_prec = prec
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
return BigDecimal(-1) if exp_prec <= 0
|
|
576
|
+
|
|
577
|
+
exp = exp(x, exp_prec)
|
|
578
|
+
|
|
579
|
+
if exp.exponent > prec + BigDecimal.double_fig
|
|
580
|
+
# Workaroudn for https://github.com/ruby/bigdecimal/issues/464
|
|
581
|
+
exp
|
|
582
|
+
else
|
|
583
|
+
exp.sub(1, prec)
|
|
584
|
+
end
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
# erf(decimal, numeric) -> BigDecimal
|
|
588
|
+
#
|
|
589
|
+
# Computes the error function of +decimal+ to the specified number of digits of
|
|
590
|
+
# precision, +numeric+.
|
|
591
|
+
#
|
|
592
|
+
# If +decimal+ is NaN, returns NaN.
|
|
593
|
+
#
|
|
594
|
+
# BigMath.erf(BigDecimal('1'), 32).to_s
|
|
595
|
+
# #=> "0.84270079294971486934122063508261e0"
|
|
596
|
+
#
|
|
597
|
+
def erf(x, prec)
|
|
598
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :erf)
|
|
599
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :erf)
|
|
600
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
601
|
+
return BigDecimal(x.infinite?) if x.infinite?
|
|
602
|
+
return BigDecimal(0) if x == 0
|
|
603
|
+
return -erf(-x, prec) if x < 0
|
|
604
|
+
return BigDecimal(1) if x > 5000000000 # erf(5000000000) > 1 - 1e-10000000000000000000
|
|
605
|
+
|
|
606
|
+
if x > 8
|
|
607
|
+
xf = x.to_f
|
|
608
|
+
log10_erfc = -xf ** 2 / Math.log(10) - Math.log10(xf * Math::PI ** 0.5)
|
|
609
|
+
erfc_prec = [prec + log10_erfc.ceil, 1].max
|
|
610
|
+
erfc = _erfc_asymptotic(x, erfc_prec)
|
|
611
|
+
if erfc
|
|
612
|
+
# Workaround for https://github.com/ruby/bigdecimal/issues/464
|
|
613
|
+
return BigDecimal(1) if erfc.exponent < -prec - BigDecimal.double_fig
|
|
614
|
+
|
|
615
|
+
return BigDecimal(1).sub(erfc, prec)
|
|
616
|
+
end
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
prec2 = prec + BigDecimal.double_fig
|
|
620
|
+
x_smallprec = x.mult(1, Integer.sqrt(prec2) / 2)
|
|
621
|
+
# Taylor series of x with small precision is fast
|
|
622
|
+
erf1 = _erf_taylor(x_smallprec, BigDecimal(0), BigDecimal(0), prec2)
|
|
623
|
+
# Taylor series converges quickly for small x
|
|
624
|
+
_erf_taylor(x - x_smallprec, x_smallprec, erf1, prec2).mult(1, prec)
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
# call-seq:
|
|
628
|
+
# erfc(decimal, numeric) -> BigDecimal
|
|
629
|
+
#
|
|
630
|
+
# Computes the complementary error function of +decimal+ to the specified number of digits of
|
|
631
|
+
# precision, +numeric+.
|
|
632
|
+
#
|
|
633
|
+
# If +decimal+ is NaN, returns NaN.
|
|
634
|
+
#
|
|
635
|
+
# BigMath.erfc(BigDecimal('10'), 32).to_s
|
|
636
|
+
# #=> "0.20884875837625447570007862949578e-44"
|
|
637
|
+
#
|
|
638
|
+
def erfc(x, prec)
|
|
639
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :erfc)
|
|
640
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :erfc)
|
|
641
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
642
|
+
return BigDecimal(1 - x.infinite?) if x.infinite?
|
|
643
|
+
return BigDecimal(1).sub(erf(x, prec + BigDecimal.double_fig), prec) if x < 0
|
|
644
|
+
return BigDecimal(0) if x > 5000000000 # erfc(5000000000) < 1e-10000000000000000000 (underflow)
|
|
645
|
+
|
|
646
|
+
if x >= 8
|
|
647
|
+
y = _erfc_asymptotic(x, prec)
|
|
648
|
+
return y.mult(1, prec) if y
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
# erfc(x) = 1 - erf(x) < exp(-x**2)/x/sqrt(pi)
|
|
652
|
+
# Precision of erf(x) needs about log10(exp(-x**2)) extra digits
|
|
653
|
+
log10 = 2.302585092994046
|
|
654
|
+
high_prec = prec + BigDecimal.double_fig + (x.ceil**2 / log10).ceil
|
|
655
|
+
BigDecimal(1).sub(erf(x, high_prec), prec)
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
# Calculates erf(x + a)
|
|
659
|
+
private_class_method def _erf_taylor(x, a, erf_a, prec) # :nodoc:
|
|
660
|
+
return erf_a if x.zero?
|
|
661
|
+
# Let f(x+a) = erf(x+a)*exp((x+a)**2)*sqrt(pi)/2
|
|
662
|
+
# = c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + ...
|
|
663
|
+
# f'(x+a) = 1+2*(x+a)*f(x+a)
|
|
664
|
+
# f'(x+a) = c1 + 2*c2*x + 3*c3*x**2 + 4*c4*x**3 + 5*c5*x**4 + ...
|
|
665
|
+
# = 1+2*(x+a)*(c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + ...)
|
|
666
|
+
# therefore,
|
|
667
|
+
# c0 = f(a)
|
|
668
|
+
# c1 = 2 * a * c0 + 1
|
|
669
|
+
# c2 = (2 * c0 + 2 * a * c1) / 2
|
|
670
|
+
# c3 = (2 * c1 + 2 * a * c2) / 3
|
|
671
|
+
# c4 = (2 * c2 + 2 * a * c3) / 4
|
|
672
|
+
#
|
|
673
|
+
# All coefficients are positive when a >= 0
|
|
674
|
+
|
|
675
|
+
scale = BigDecimal(2).div(sqrt(PI(prec), prec), prec)
|
|
676
|
+
c_prev = erf_a.div(scale.mult(exp(-a*a, prec), prec), prec)
|
|
677
|
+
c_next = (2 * a * c_prev).add(1, prec).mult(x, prec)
|
|
678
|
+
sum = c_prev.add(c_next, prec)
|
|
679
|
+
|
|
680
|
+
2.step do |k|
|
|
681
|
+
c = (c_prev.mult(x, prec) + a * c_next).mult(2, prec).mult(x, prec).div(k, prec)
|
|
682
|
+
sum = sum.add(c, prec)
|
|
683
|
+
c_prev, c_next = c_next, c
|
|
684
|
+
break if [c_prev, c_next].all? { |c| c.zero? || (c.exponent < sum.exponent - prec) }
|
|
685
|
+
end
|
|
686
|
+
value = sum.mult(scale.mult(exp(-(x + a).mult(x + a, prec), prec), prec), prec)
|
|
687
|
+
value > 1 ? BigDecimal(1) : value
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
private_class_method def _erfc_asymptotic(x, prec) # :nodoc:
|
|
691
|
+
# Let f(x) = erfc(x)*sqrt(pi)*exp(x**2)/2
|
|
692
|
+
# f(x) satisfies the following differential equation:
|
|
693
|
+
# 2*x*f(x) = f'(x) + 1
|
|
694
|
+
# From the above equation, we can derive the following asymptotic expansion:
|
|
695
|
+
# f(x) = (0..kmax).sum { (-1)**k * (2*k)! / 4**k / k! / x**(2*k)) } / x
|
|
696
|
+
|
|
697
|
+
# This asymptotic expansion does not converge.
|
|
698
|
+
# But if there is a k that satisfies (2*k)! / 4**k / k! / x**(2*k) < 10**(-prec),
|
|
699
|
+
# It is enough to calculate erfc within the given precision.
|
|
700
|
+
# Using Stirling's approximation, we can simplify this condition to:
|
|
701
|
+
# sqrt(2)/2 + k*log(k) - k - 2*k*log(x) < -prec*log(10)
|
|
702
|
+
# and the left side is minimized when k = x**2.
|
|
703
|
+
prec += BigDecimal.double_fig
|
|
704
|
+
xf = x.to_f
|
|
705
|
+
kmax = (1..(xf ** 2).floor).bsearch do |k|
|
|
706
|
+
Math.log(2) / 2 + k * Math.log(k) - k - 2 * k * Math.log(xf) < -prec * Math.log(10)
|
|
707
|
+
end
|
|
708
|
+
return unless kmax
|
|
709
|
+
|
|
710
|
+
sum = BigDecimal(1)
|
|
711
|
+
x2 = x.mult(x, prec)
|
|
712
|
+
d = BigDecimal(1)
|
|
713
|
+
(1..kmax).each do |k|
|
|
714
|
+
d = d.div(x2, prec).mult(1 - 2 * k, prec).div(2, prec)
|
|
715
|
+
sum = sum.add(d, prec)
|
|
716
|
+
end
|
|
717
|
+
sum.div(exp(x2, prec).mult(PI(prec).sqrt(prec), prec), prec).div(x, prec)
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
# call-seq:
|
|
721
|
+
# BigMath.gamma(decimal, numeric) -> BigDecimal
|
|
722
|
+
#
|
|
723
|
+
# Computes the gamma function of +decimal+ to the specified number of
|
|
724
|
+
# digits of precision, +numeric+.
|
|
725
|
+
#
|
|
726
|
+
# BigMath.gamma(BigDecimal('0.5'), 32).to_s
|
|
727
|
+
# #=> "0.17724538509055160272981674833411e1"
|
|
728
|
+
#
|
|
729
|
+
def gamma(x, prec)
|
|
730
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :gamma)
|
|
731
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :gamma)
|
|
732
|
+
prec2 = prec + BigDecimal.double_fig
|
|
733
|
+
if x < 0.5
|
|
734
|
+
raise Math::DomainError, 'Numerical argument is out of domain - gamma' if x.frac.zero?
|
|
735
|
+
|
|
736
|
+
# Euler's reflection formula: gamma(z) * gamma(1-z) = pi/sin(pi*z)
|
|
737
|
+
pi = PI(prec2)
|
|
738
|
+
sin = _sinpix(x, pi, prec2)
|
|
739
|
+
return pi.div(gamma(1 - x, prec2).mult(sin, prec2), prec)
|
|
740
|
+
elsif x.frac.zero? && x < 1000 * prec
|
|
741
|
+
return _gamma_positive_integer(x, prec2).mult(1, prec)
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
a, sum = _gamma_spouge_sum_part(x, prec2)
|
|
745
|
+
(x + (a - 1)).power(x - 0.5, prec2).mult(BigMath.exp(1 - x, prec2), prec2).mult(sum, prec)
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
# call-seq:
|
|
749
|
+
# BigMath.lgamma(decimal, numeric) -> [BigDecimal, Integer]
|
|
750
|
+
#
|
|
751
|
+
# Computes the natural logarithm of the absolute value of the gamma function
|
|
752
|
+
# of +decimal+ to the specified number of digits of precision, +numeric+ and its sign.
|
|
753
|
+
#
|
|
754
|
+
# BigMath.lgamma(BigDecimal('0.5'), 32)
|
|
755
|
+
# #=> [0.57236494292470008707171367567653e0, 1]
|
|
756
|
+
#
|
|
757
|
+
def lgamma(x, prec)
|
|
758
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :lgamma)
|
|
759
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :lgamma)
|
|
760
|
+
prec2 = prec + BigDecimal.double_fig
|
|
761
|
+
if x < 0.5
|
|
762
|
+
return [BigDecimal::INFINITY, 1] if x.frac.zero?
|
|
763
|
+
|
|
764
|
+
loop do
|
|
765
|
+
# Euler's reflection formula: gamma(z) * gamma(1-z) = pi/sin(pi*z)
|
|
766
|
+
pi = PI(prec2)
|
|
767
|
+
sin = _sinpix(x, pi, prec2)
|
|
768
|
+
log_gamma = BigMath.log(pi, prec2).sub(lgamma(1 - x, prec2).first + BigMath.log(sin.abs, prec2), prec)
|
|
769
|
+
return [log_gamma, sin > 0 ? 1 : -1] if prec2 + log_gamma.exponent > prec + BigDecimal.double_fig
|
|
770
|
+
|
|
771
|
+
# Retry with higher precision if loss of significance is too large
|
|
772
|
+
prec2 = prec2 * 3 / 2
|
|
773
|
+
end
|
|
774
|
+
elsif x.frac.zero? && x < 1000 * prec
|
|
775
|
+
log_gamma = BigMath.log(_gamma_positive_integer(x, prec2), prec)
|
|
776
|
+
[log_gamma, 1]
|
|
777
|
+
else
|
|
778
|
+
# if x is close to 1 or 2, increase precision to reduce loss of significance
|
|
779
|
+
diff1_exponent = (x - 1).exponent
|
|
780
|
+
diff2_exponent = (x - 2).exponent
|
|
781
|
+
extra_prec = [-diff1_exponent, -diff2_exponent, 0].max
|
|
782
|
+
extremely_near_one = diff1_exponent < -prec2
|
|
783
|
+
extremely_near_two = diff2_exponent < -prec2
|
|
784
|
+
|
|
785
|
+
if extremely_near_one || extremely_near_two
|
|
786
|
+
# If x is extreamely close to base = 1 or 2, linear interpolation is accurate enough.
|
|
787
|
+
# Taylor expansion at x = base is: (x - base) * digamma(base) + (x - base) ** 2 * trigamma(base) / 2 + ...
|
|
788
|
+
# And we can ignore (x - base) ** 2 and higher order terms.
|
|
789
|
+
base = extremely_near_one ? 1 : 2
|
|
790
|
+
d = BigDecimal(1)._decimal_shift(1 - prec2)
|
|
791
|
+
log_gamma_d, sign = lgamma(base + d, prec2)
|
|
792
|
+
return [log_gamma_d.mult(x - base, prec2).div(d, prec), sign]
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
prec2 += [-diff1_exponent, -diff2_exponent, 0].max
|
|
796
|
+
a, sum = _gamma_spouge_sum_part(x, prec2)
|
|
797
|
+
log_gamma = BigMath.log(sum, prec2).add((x - 0.5).mult(BigMath.log(x.add(a - 1, prec2), prec2), prec2) + 1 - x, prec)
|
|
798
|
+
[log_gamma, 1]
|
|
799
|
+
end
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
# Returns sum part: sqrt(2*pi) and c[k]/(x+k) terms of Spouge's approximation
|
|
803
|
+
private_class_method def _gamma_spouge_sum_part(x, prec) # :nodoc:
|
|
804
|
+
x -= 1
|
|
805
|
+
# Spouge's approximation
|
|
806
|
+
# x! = (x + a)**(x + 0.5) * exp(-x - a) * (sqrt(2 * pi) + (1..a - 1).sum{|k| c[k] / (x + k) } + epsilon)
|
|
807
|
+
# where c[k] = (-1)**k * (a - k)**(k - 0.5) * exp(a - k) / (k - 1)!
|
|
808
|
+
# and epsilon is bounded by a**(-0.5) * (2 * pi) ** (-a - 0.5)
|
|
809
|
+
|
|
810
|
+
# Estimate required a for given precision
|
|
811
|
+
a = (prec / Math.log10(2 * Math::PI)).ceil
|
|
812
|
+
|
|
813
|
+
# Calculate exponent of c[k] in low precision to estimate required precision
|
|
814
|
+
low_prec = 16
|
|
815
|
+
log10f = Math.log(10)
|
|
816
|
+
x_low_prec = x.mult(1, low_prec)
|
|
817
|
+
loggamma_k = 0
|
|
818
|
+
ck_exponents = (1..a-1).map do |k|
|
|
819
|
+
loggamma_k += Math.log10(k - 1) if k > 1
|
|
820
|
+
-loggamma_k - k / log10f + (k - 0.5) * Math.log10(a - k) - BigMath.log10(x_low_prec.add(k, low_prec), low_prec)
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
# Estimate exponent of sum by Stirling's approximation
|
|
824
|
+
approx_sum_exponent = x < 1 ? -Math.log10(a) / 2 : Math.log10(2 * Math::PI) / 2 + x_low_prec.add(0.5, low_prec) * Math.log10(x_low_prec / x_low_prec.add(a, low_prec))
|
|
825
|
+
|
|
826
|
+
# Determine required precision of c[k]
|
|
827
|
+
prec2 = [ck_exponents.max.ceil - approx_sum_exponent.floor, 0].max + prec
|
|
828
|
+
|
|
829
|
+
einv = BigMath.exp(-1, prec2)
|
|
830
|
+
sum = (PI(prec) * 2).sqrt(prec).mult(BigMath.exp(-a, prec), prec)
|
|
831
|
+
y = BigDecimal(1)
|
|
832
|
+
(1..a - 1).each do |k|
|
|
833
|
+
# c[k] = (-1)**k * (a - k)**(k - 0.5) * exp(-k) / (k-1)! / (x + k)
|
|
834
|
+
y = y.div(1 - k, prec2) if k > 1
|
|
835
|
+
y = y.mult(einv, prec2)
|
|
836
|
+
z = y.mult(BigDecimal((a - k) ** k), prec2).div(BigDecimal(a - k).sqrt(prec2).mult(x.add(k, prec2), prec2), prec2)
|
|
837
|
+
# sum += c[k] / (x + k)
|
|
838
|
+
sum = sum.add(z, prec2)
|
|
839
|
+
end
|
|
840
|
+
[a, sum]
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
private_class_method def _gamma_positive_integer(x, prec) # :nodoc:
|
|
844
|
+
return x if x == 1
|
|
845
|
+
numbers = (1..x - 1).map {|i| BigDecimal(i) }
|
|
846
|
+
while numbers.size > 1
|
|
847
|
+
numbers = numbers.each_slice(2).map {|a, b| b ? a.mult(b, prec) : a }
|
|
848
|
+
end
|
|
849
|
+
numbers.first
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
# Returns sin(pi * x), for gamma reflection formula calculation
|
|
853
|
+
private_class_method def _sinpix(x, pi, prec) # :nodoc:
|
|
854
|
+
x = x % 2
|
|
855
|
+
sign = x > 1 ? -1 : 1
|
|
856
|
+
x %= 1
|
|
857
|
+
x = 1 - x if x > 0.5 # to avoid sin(pi*x) loss of precision for x close to 1
|
|
858
|
+
sign * sin(x.mult(pi, prec), prec)
|
|
859
|
+
end
|
|
860
|
+
|
|
861
|
+
# call-seq:
|
|
862
|
+
# frexp(x) -> [BigDecimal, Integer]
|
|
863
|
+
#
|
|
864
|
+
# Decomposes +x+ into a normalized fraction and an integral power of ten.
|
|
865
|
+
#
|
|
866
|
+
# BigMath.frexp(BigDecimal(123.456))
|
|
867
|
+
# #=> [0.123456e0, 3]
|
|
868
|
+
#
|
|
869
|
+
def frexp(x)
|
|
870
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, 0, :frexp)
|
|
871
|
+
return [x, 0] unless x.finite?
|
|
872
|
+
|
|
873
|
+
exponent = x.exponent
|
|
874
|
+
[x._decimal_shift(-exponent), exponent]
|
|
875
|
+
end
|
|
876
|
+
|
|
877
|
+
# call-seq:
|
|
878
|
+
# ldexp(fraction, exponent) -> BigDecimal
|
|
879
|
+
#
|
|
880
|
+
# Inverse of +frexp+.
|
|
881
|
+
# Returns the value of fraction * 10**exponent.
|
|
882
|
+
#
|
|
883
|
+
# BigMath.ldexp(BigDecimal("0.123456e0"), 3)
|
|
884
|
+
# #=> 0.123456e3
|
|
885
|
+
#
|
|
886
|
+
def ldexp(x, exponent)
|
|
887
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, 0, :ldexp)
|
|
888
|
+
x.finite? ? x._decimal_shift(exponent) : x
|
|
889
|
+
end
|
|
890
|
+
|
|
191
891
|
# call-seq:
|
|
192
892
|
# PI(numeric) -> BigDecimal
|
|
193
893
|
#
|
|
@@ -198,7 +898,7 @@ module BigMath
|
|
|
198
898
|
# #=> "0.31415926535897932384626433832795e1"
|
|
199
899
|
#
|
|
200
900
|
def PI(prec)
|
|
201
|
-
BigDecimal::Internal.
|
|
901
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :PI)
|
|
202
902
|
n = prec + BigDecimal.double_fig
|
|
203
903
|
zero = BigDecimal("0")
|
|
204
904
|
one = BigDecimal("1")
|
|
@@ -243,7 +943,7 @@ module BigMath
|
|
|
243
943
|
# #=> "0.27182818284590452353602874713527e1"
|
|
244
944
|
#
|
|
245
945
|
def E(prec)
|
|
246
|
-
BigDecimal::Internal.
|
|
247
|
-
|
|
946
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :E)
|
|
947
|
+
exp(1, prec)
|
|
248
948
|
end
|
|
249
949
|
end
|
data/lib/bigdecimal/newton.rb
CHANGED
data/lib/bigdecimal.rb
CHANGED
|
@@ -27,13 +27,24 @@ class BigDecimal
|
|
|
27
27
|
raise ArgumentError, "#{x.inspect} can't be coerced into BigDecimal"
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def self.
|
|
31
|
-
|
|
30
|
+
def self.coerce_validate_prec(prec, method_name, accept_zero: false) # :nodoc:
|
|
31
|
+
unless Integer === prec
|
|
32
|
+
original = prec
|
|
33
|
+
# Emulate Integer.try_convert for ruby < 3.1
|
|
34
|
+
if prec.respond_to?(:to_int)
|
|
35
|
+
prec = prec.to_int
|
|
36
|
+
else
|
|
37
|
+
raise TypeError, "no implicit conversion of #{original.class} into Integer"
|
|
38
|
+
end
|
|
39
|
+
raise TypeError, "can't convert #{original.class} to Integer" unless Integer === prec
|
|
40
|
+
end
|
|
41
|
+
|
|
32
42
|
if accept_zero
|
|
33
43
|
raise ArgumentError, "Negative precision for #{method_name}" if prec < 0
|
|
34
44
|
else
|
|
35
45
|
raise ArgumentError, "Zero or negative precision for #{method_name}" if prec <= 0
|
|
36
46
|
end
|
|
47
|
+
prec
|
|
37
48
|
end
|
|
38
49
|
|
|
39
50
|
def self.infinity_computation_result # :nodoc:
|
|
@@ -83,10 +94,10 @@ class BigDecimal
|
|
|
83
94
|
#
|
|
84
95
|
# Also available as the operator **.
|
|
85
96
|
#
|
|
86
|
-
def power(y, prec =
|
|
87
|
-
Internal.
|
|
97
|
+
def power(y, prec = 0)
|
|
98
|
+
prec = Internal.coerce_validate_prec(prec, :power, accept_zero: true)
|
|
88
99
|
x = self
|
|
89
|
-
y = Internal.coerce_to_bigdecimal(y, prec || n_significant_digits, :power)
|
|
100
|
+
y = Internal.coerce_to_bigdecimal(y, prec.nonzero? || n_significant_digits, :power)
|
|
90
101
|
|
|
91
102
|
return Internal.nan_computation_result if x.nan? || y.nan?
|
|
92
103
|
return BigDecimal(1) if y.zero?
|
|
@@ -133,10 +144,10 @@ class BigDecimal
|
|
|
133
144
|
return BigDecimal(1)
|
|
134
145
|
end
|
|
135
146
|
|
|
136
|
-
|
|
147
|
+
limit = BigDecimal.limit
|
|
137
148
|
frac_part = y.frac
|
|
138
149
|
|
|
139
|
-
if frac_part.zero? &&
|
|
150
|
+
if frac_part.zero? && prec.zero? && limit.zero?
|
|
140
151
|
# Infinite precision calculation for `x ** int` and `x.power(int)`
|
|
141
152
|
int_part = y.fix.to_i
|
|
142
153
|
int_part = -int_part if (neg = int_part < 0)
|
|
@@ -156,18 +167,19 @@ class BigDecimal
|
|
|
156
167
|
return neg ? BigDecimal(1) / ans : ans
|
|
157
168
|
end
|
|
158
169
|
|
|
159
|
-
prec
|
|
170
|
+
result_prec = prec.nonzero? || [x.n_significant_digits, y.n_significant_digits, BigDecimal.double_fig].max + BigDecimal.double_fig
|
|
171
|
+
result_prec = [result_prec, limit].min if prec.zero? && limit.nonzero?
|
|
172
|
+
|
|
173
|
+
prec2 = result_prec + BigDecimal.double_fig
|
|
160
174
|
|
|
161
175
|
if y < 0
|
|
162
|
-
inv = x.power(-y,
|
|
176
|
+
inv = x.power(-y, prec2)
|
|
163
177
|
return BigDecimal(0) if inv.infinite?
|
|
164
178
|
return BigDecimal::Internal.infinity_computation_result if inv.zero?
|
|
165
|
-
return BigDecimal(1).div(inv,
|
|
179
|
+
return BigDecimal(1).div(inv, result_prec)
|
|
166
180
|
end
|
|
167
181
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if frac_part.zero? && y.exponent < Math.log(prec) * 5 + 20
|
|
182
|
+
if frac_part.zero? && y.exponent < Math.log(result_prec) * 5 + 20
|
|
171
183
|
# Use exponentiation by squaring if y is an integer and not too large
|
|
172
184
|
pow_prec = prec2 + y.exponent
|
|
173
185
|
n = 1
|
|
@@ -180,16 +192,16 @@ class BigDecimal
|
|
|
180
192
|
break if n > int_part
|
|
181
193
|
xn = xn.mult(xn, pow_prec)
|
|
182
194
|
end
|
|
183
|
-
ans.mult(1,
|
|
195
|
+
ans.mult(1, result_prec)
|
|
184
196
|
else
|
|
185
|
-
if x > 1
|
|
197
|
+
if x > 1 && x.finite?
|
|
186
198
|
# To calculate exp(z, prec), z needs prec+max(z.exponent, 0) precision if z > 0.
|
|
187
199
|
# Estimate (y*log(x)).exponent
|
|
188
200
|
logx_exponent = x < 2 ? (x - 1).exponent : Math.log10(x.exponent).round
|
|
189
201
|
ylogx_exponent = y.exponent + logx_exponent
|
|
190
202
|
prec2 += [ylogx_exponent, 0].max
|
|
191
203
|
end
|
|
192
|
-
BigMath.exp(BigMath.log(x, prec2).mult(y, prec2),
|
|
204
|
+
BigMath.exp(BigMath.log(x, prec2).mult(y, prec2), result_prec)
|
|
193
205
|
end
|
|
194
206
|
end
|
|
195
207
|
|
|
@@ -198,7 +210,7 @@ class BigDecimal
|
|
|
198
210
|
# Result has at least prec significant digits.
|
|
199
211
|
#
|
|
200
212
|
def sqrt(prec)
|
|
201
|
-
Internal.
|
|
213
|
+
prec = Internal.coerce_validate_prec(prec, :sqrt, accept_zero: true)
|
|
202
214
|
return Internal.infinity_computation_result if infinite? == 1
|
|
203
215
|
|
|
204
216
|
raise FloatDomainError, 'sqrt of negative value' if self < 0
|
|
@@ -206,7 +218,9 @@ class BigDecimal
|
|
|
206
218
|
return self if zero?
|
|
207
219
|
|
|
208
220
|
if prec == 0
|
|
209
|
-
|
|
221
|
+
limit = BigDecimal.limit
|
|
222
|
+
prec = n_significant_digits + BigDecimal.double_fig
|
|
223
|
+
prec = [limit, prec].min if limit.nonzero?
|
|
210
224
|
end
|
|
211
225
|
|
|
212
226
|
ex = exponent / 2
|
|
@@ -224,6 +238,7 @@ end
|
|
|
224
238
|
# Core BigMath methods for BigDecimal (log, exp) are defined here.
|
|
225
239
|
# Other methods (sin, cos, atan) are defined in 'bigdecimal/math.rb'.
|
|
226
240
|
module BigMath
|
|
241
|
+
module_function
|
|
227
242
|
|
|
228
243
|
# call-seq:
|
|
229
244
|
# BigMath.log(decimal, numeric) -> BigDecimal
|
|
@@ -237,8 +252,8 @@ module BigMath
|
|
|
237
252
|
#
|
|
238
253
|
# If +decimal+ is NaN, returns NaN.
|
|
239
254
|
#
|
|
240
|
-
def
|
|
241
|
-
BigDecimal::Internal.
|
|
255
|
+
def log(x, prec)
|
|
256
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :log)
|
|
242
257
|
raise Math::DomainError, 'Complex argument for BigMath.log' if Complex === x
|
|
243
258
|
|
|
244
259
|
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :log)
|
|
@@ -292,7 +307,7 @@ module BigMath
|
|
|
292
307
|
end
|
|
293
308
|
|
|
294
309
|
# Taylor series for exp(x) around 0
|
|
295
|
-
private_class_method def
|
|
310
|
+
private_class_method def _exp_taylor(x, prec) # :nodoc:
|
|
296
311
|
xn = BigDecimal(1)
|
|
297
312
|
y = BigDecimal(1)
|
|
298
313
|
1.step do |i|
|
|
@@ -314,8 +329,8 @@ module BigMath
|
|
|
314
329
|
#
|
|
315
330
|
# If +decimal+ is NaN, returns NaN.
|
|
316
331
|
#
|
|
317
|
-
def
|
|
318
|
-
BigDecimal::Internal.
|
|
332
|
+
def exp(x, prec)
|
|
333
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :exp)
|
|
319
334
|
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :exp)
|
|
320
335
|
return BigDecimal::Internal.nan_computation_result if x.nan?
|
|
321
336
|
return x.positive? ? BigDecimal::Internal.infinity_computation_result : BigDecimal(0) if x.infinite?
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bigdecimal
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 4.0.0
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- Kenta Murata
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
- Shigeo Kobayashi
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
13
|
dependencies: []
|
|
14
14
|
description: This library provides arbitrary-precision decimal floating-point number
|
|
15
15
|
class.
|
|
@@ -50,7 +50,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
50
50
|
- !ruby/object:Gem::Version
|
|
51
51
|
version: '0'
|
|
52
52
|
requirements: []
|
|
53
|
-
rubygems_version: 3.6.
|
|
53
|
+
rubygems_version: 3.6.9
|
|
54
54
|
specification_version: 4
|
|
55
55
|
summary: Arbitrary-precision decimal floating-point number library.
|
|
56
56
|
test_files: []
|