bigdecimal 3.3.1-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 +703 -3
- data/lib/bigdecimal/newton.rb +2 -0
- data/lib/bigdecimal.rb +19 -15
- 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
|
#
|
|
@@ -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
|
#
|
|
@@ -148,6 +216,57 @@ module BigMath
|
|
|
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
|
#
|
|
@@ -167,7 +286,7 @@ module BigMath
|
|
|
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
|
#
|
|
@@ -244,6 +944,6 @@ module BigMath
|
|
|
244
944
|
#
|
|
245
945
|
def E(prec)
|
|
246
946
|
prec = BigDecimal::Internal.coerce_validate_prec(prec, :E)
|
|
247
|
-
|
|
947
|
+
exp(1, prec)
|
|
248
948
|
end
|
|
249
949
|
end
|
data/lib/bigdecimal/newton.rb
CHANGED
data/lib/bigdecimal.rb
CHANGED
|
@@ -144,10 +144,10 @@ class BigDecimal
|
|
|
144
144
|
return BigDecimal(1)
|
|
145
145
|
end
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
limit = BigDecimal.limit
|
|
148
148
|
frac_part = y.frac
|
|
149
149
|
|
|
150
|
-
if frac_part.zero? && prec.zero?
|
|
150
|
+
if frac_part.zero? && prec.zero? && limit.zero?
|
|
151
151
|
# Infinite precision calculation for `x ** int` and `x.power(int)`
|
|
152
152
|
int_part = y.fix.to_i
|
|
153
153
|
int_part = -int_part if (neg = int_part < 0)
|
|
@@ -167,18 +167,19 @@ class BigDecimal
|
|
|
167
167
|
return neg ? BigDecimal(1) / ans : ans
|
|
168
168
|
end
|
|
169
169
|
|
|
170
|
-
|
|
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
|
|
171
174
|
|
|
172
175
|
if y < 0
|
|
173
|
-
inv = x.power(-y,
|
|
176
|
+
inv = x.power(-y, prec2)
|
|
174
177
|
return BigDecimal(0) if inv.infinite?
|
|
175
178
|
return BigDecimal::Internal.infinity_computation_result if inv.zero?
|
|
176
|
-
return BigDecimal(1).div(inv,
|
|
179
|
+
return BigDecimal(1).div(inv, result_prec)
|
|
177
180
|
end
|
|
178
181
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if frac_part.zero? && y.exponent < Math.log(prec) * 5 + 20
|
|
182
|
+
if frac_part.zero? && y.exponent < Math.log(result_prec) * 5 + 20
|
|
182
183
|
# Use exponentiation by squaring if y is an integer and not too large
|
|
183
184
|
pow_prec = prec2 + y.exponent
|
|
184
185
|
n = 1
|
|
@@ -191,16 +192,16 @@ class BigDecimal
|
|
|
191
192
|
break if n > int_part
|
|
192
193
|
xn = xn.mult(xn, pow_prec)
|
|
193
194
|
end
|
|
194
|
-
ans.mult(1,
|
|
195
|
+
ans.mult(1, result_prec)
|
|
195
196
|
else
|
|
196
|
-
if x > 1
|
|
197
|
+
if x > 1 && x.finite?
|
|
197
198
|
# To calculate exp(z, prec), z needs prec+max(z.exponent, 0) precision if z > 0.
|
|
198
199
|
# Estimate (y*log(x)).exponent
|
|
199
200
|
logx_exponent = x < 2 ? (x - 1).exponent : Math.log10(x.exponent).round
|
|
200
201
|
ylogx_exponent = y.exponent + logx_exponent
|
|
201
202
|
prec2 += [ylogx_exponent, 0].max
|
|
202
203
|
end
|
|
203
|
-
BigMath.exp(BigMath.log(x, prec2).mult(y, prec2),
|
|
204
|
+
BigMath.exp(BigMath.log(x, prec2).mult(y, prec2), result_prec)
|
|
204
205
|
end
|
|
205
206
|
end
|
|
206
207
|
|
|
@@ -217,7 +218,9 @@ class BigDecimal
|
|
|
217
218
|
return self if zero?
|
|
218
219
|
|
|
219
220
|
if prec == 0
|
|
220
|
-
|
|
221
|
+
limit = BigDecimal.limit
|
|
222
|
+
prec = n_significant_digits + BigDecimal.double_fig
|
|
223
|
+
prec = [limit, prec].min if limit.nonzero?
|
|
221
224
|
end
|
|
222
225
|
|
|
223
226
|
ex = exponent / 2
|
|
@@ -235,6 +238,7 @@ end
|
|
|
235
238
|
# Core BigMath methods for BigDecimal (log, exp) are defined here.
|
|
236
239
|
# Other methods (sin, cos, atan) are defined in 'bigdecimal/math.rb'.
|
|
237
240
|
module BigMath
|
|
241
|
+
module_function
|
|
238
242
|
|
|
239
243
|
# call-seq:
|
|
240
244
|
# BigMath.log(decimal, numeric) -> BigDecimal
|
|
@@ -248,7 +252,7 @@ module BigMath
|
|
|
248
252
|
#
|
|
249
253
|
# If +decimal+ is NaN, returns NaN.
|
|
250
254
|
#
|
|
251
|
-
def
|
|
255
|
+
def log(x, prec)
|
|
252
256
|
prec = BigDecimal::Internal.coerce_validate_prec(prec, :log)
|
|
253
257
|
raise Math::DomainError, 'Complex argument for BigMath.log' if Complex === x
|
|
254
258
|
|
|
@@ -303,7 +307,7 @@ module BigMath
|
|
|
303
307
|
end
|
|
304
308
|
|
|
305
309
|
# Taylor series for exp(x) around 0
|
|
306
|
-
private_class_method def
|
|
310
|
+
private_class_method def _exp_taylor(x, prec) # :nodoc:
|
|
307
311
|
xn = BigDecimal(1)
|
|
308
312
|
y = BigDecimal(1)
|
|
309
313
|
1.step do |i|
|
|
@@ -325,7 +329,7 @@ module BigMath
|
|
|
325
329
|
#
|
|
326
330
|
# If +decimal+ is NaN, returns NaN.
|
|
327
331
|
#
|
|
328
|
-
def
|
|
332
|
+
def exp(x, prec)
|
|
329
333
|
prec = BigDecimal::Internal.coerce_validate_prec(prec, :exp)
|
|
330
334
|
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :exp)
|
|
331
335
|
return BigDecimal::Internal.nan_computation_result if x.nan?
|
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: []
|