bigdecimal 3.2.3 → 4.1.1

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