bigdecimal 4.0.1-java → 4.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0fa1b65ea52d18df3728073b1a3b78469212549f02de5a8903bf4dc039285d95
4
- data.tar.gz: dc2848702fb24e465a42e3f19deb7006e8cb1d6cf89140ce7e828e933e5e3596
3
+ metadata.gz: dbec3e510145cedb03e4d1813d6e0ab22ff1327ee817ea9d2347e780fe6d5bf1
4
+ data.tar.gz: 9442152d34a18fd79367606134622d028468edf23d6dbe3404a9eaf239788f20
5
5
  SHA512:
6
- metadata.gz: 25472e0e989a45ed8dc4e4f91ce1d2dbf1ba598a6513ad20278d41c305bc7341257a37ea5f050854d3a0a1c4344bd7fdadef0eec4ceb9bffcbbfc0eb6067c1ba
7
- data.tar.gz: 040b7c0906dc8c4ce3adc4b29d12d19869eb828cdc7fecb48e0f1c9bf830ea5539fe505bfb3fc333071e806eec75ae060178fc5d88800c2a84f0b3783373838b
6
+ metadata.gz: d315846a325bdba82e62e2fe34b16a8ef01942e4485d6551e835c1739484b854593c33a7d568f10e461a27276ade554d0e80bb75666008d9502538d35867d513
7
+ data.tar.gz: 7f0bf10269c3c1b3135b8d4b3dff286e5a7ad9c2f13c976f333ce3191c4fbe565f9ba35c19d041b2fbaa7bb2d7ede35e17d816c1cfb7357426f6e798eff471c2
data/bigdecimal.gemspec CHANGED
@@ -34,6 +34,9 @@ Gem::Specification.new do |s|
34
34
  sample/linear.rb
35
35
  sample/nlsolve.rb
36
36
  sample/pi.rb
37
+ sig/big_decimal_util.rbs
38
+ sig/big_decimal.rbs
39
+ sig/big_math.rbs
37
40
  ]
38
41
  if Gem::Platform === s.platform and s.platform =~ 'java' or RUBY_ENGINE == 'jruby'
39
42
  s.platform = 'java'
@@ -43,15 +46,17 @@ Gem::Specification.new do |s|
43
46
  ext/bigdecimal/bigdecimal.c
44
47
  ext/bigdecimal/bigdecimal.h
45
48
  ext/bigdecimal/bits.h
49
+ ext/bigdecimal/div.h
46
50
  ext/bigdecimal/feature.h
47
51
  ext/bigdecimal/missing.c
48
52
  ext/bigdecimal/missing.h
53
+ ext/bigdecimal/ntt.h
49
54
  ext/bigdecimal/missing/dtoa.c
50
55
  ext/bigdecimal/static_assert.h
51
56
  ]
52
57
  end
53
58
 
54
- s.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
59
+ s.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
55
60
 
56
61
  s.metadata["changelog_uri"] = s.homepage + "/blob/master/CHANGES.md"
57
62
  end
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  require 'bigdecimal'
3
3
 
4
4
  #
@@ -75,8 +75,8 @@ module BigMath
75
75
  private_class_method def _sin_periodic_reduction(x, prec, add_half_pi: false) # :nodoc:
76
76
  return [1, x] if -Math::PI/2 <= x && x <= Math::PI/2 && !add_half_pi
77
77
 
78
- mod_prec = prec + BigDecimal.double_fig
79
- pi_extra_prec = [x.exponent, 0].max + BigDecimal.double_fig
78
+ mod_prec = prec + BigDecimal::Internal::EXTRA_PREC
79
+ pi_extra_prec = [x.exponent, 0].max + BigDecimal::Internal::EXTRA_PREC
80
80
  while true
81
81
  pi = PI(mod_prec + pi_extra_prec)
82
82
  half_pi = pi / 2
@@ -84,16 +84,47 @@ module BigMath
84
84
  mod -= half_pi
85
85
  if mod.zero? || mod_prec + mod.exponent <= 0
86
86
  # mod is too small to estimate required pi precision
87
- mod_prec = mod_prec * 3 / 2 + BigDecimal.double_fig
87
+ mod_prec = mod_prec * 3 / 2 + BigDecimal::Internal::EXTRA_PREC
88
88
  elsif mod_prec + mod.exponent < prec
89
89
  # Estimate required precision of pi
90
- mod_prec = prec - mod.exponent + BigDecimal.double_fig
90
+ mod_prec = prec - mod.exponent + BigDecimal::Internal::EXTRA_PREC
91
91
  else
92
92
  return [div % 2 == 0 ? 1 : -1, mod.mult(1, prec)]
93
93
  end
94
94
  end
95
95
  end
96
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
+
97
128
  # call-seq:
98
129
  # cbrt(decimal, numeric) -> BigDecimal
99
130
  #
@@ -114,9 +145,7 @@ module BigMath
114
145
  ex = x.exponent / 3
115
146
  x = x._decimal_shift(-3 * ex)
116
147
  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|
148
+ BigDecimal::Internal.newton_loop(prec + BigDecimal::Internal::EXTRA_PREC) do |p|
120
149
  y = (2 * y + x.div(y, p).div(y, p)).div(3, p)
121
150
  end
122
151
  y._decimal_shift(ex).mult(neg ? -1 : 1, prec)
@@ -137,7 +166,7 @@ module BigMath
137
166
  y = BigDecimal::Internal.coerce_to_bigdecimal(y, prec, :hypot)
138
167
  return BigDecimal::Internal.nan_computation_result if x.nan? || y.nan?
139
168
  return BigDecimal::Internal.infinity_computation_result if x.infinite? || y.infinite?
140
- prec2 = prec + BigDecimal.double_fig
169
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
141
170
  sqrt(x.mult(x, prec2) + y.mult(y, prec2), prec)
142
171
  end
143
172
 
@@ -156,26 +185,9 @@ module BigMath
156
185
  prec = BigDecimal::Internal.coerce_validate_prec(prec, :sin)
157
186
  x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :sin)
158
187
  return BigDecimal::Internal.nan_computation_result if x.infinite? || x.nan?
159
- n = prec + BigDecimal.double_fig
160
- one = BigDecimal("1")
161
- two = BigDecimal("2")
188
+ n = prec + BigDecimal::Internal::EXTRA_PREC
162
189
  sign, x = _sin_periodic_reduction(x, n)
163
- x1 = x
164
- x2 = x.mult(x,n)
165
- y = x
166
- d = y
167
- i = one
168
- z = one
169
- while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
170
- m = BigDecimal.double_fig if m < BigDecimal.double_fig
171
- x1 = -x2.mult(x1,n)
172
- i += two
173
- z *= (i-one) * i
174
- d = x1.div(z,m)
175
- y += d
176
- end
177
- y = BigDecimal("1") if y > 1
178
- y.mult(sign, prec)
190
+ _sin_around_zero(x, n).mult(sign, prec)
179
191
  end
180
192
 
181
193
  # call-seq:
@@ -193,8 +205,9 @@ module BigMath
193
205
  prec = BigDecimal::Internal.coerce_validate_prec(prec, :cos)
194
206
  x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :cos)
195
207
  return BigDecimal::Internal.nan_computation_result if x.infinite? || x.nan?
196
- sign, x = _sin_periodic_reduction(x, prec + BigDecimal.double_fig, add_half_pi: true)
197
- sign * sin(x, prec)
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)
198
211
  end
199
212
 
200
213
  # call-seq:
@@ -213,7 +226,8 @@ module BigMath
213
226
  #
214
227
  def tan(x, prec)
215
228
  prec = BigDecimal::Internal.coerce_validate_prec(prec, :tan)
216
- sin(x, prec + BigDecimal.double_fig).div(cos(x, prec + BigDecimal.double_fig), prec)
229
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
230
+ sin(x, prec2).div(cos(x, prec2), prec)
217
231
  end
218
232
 
219
233
  # call-seq:
@@ -233,7 +247,7 @@ module BigMath
233
247
  raise Math::DomainError, "Out of domain argument for asin" if x < -1 || x > 1
234
248
  return BigDecimal::Internal.nan_computation_result if x.nan?
235
249
 
236
- prec2 = prec + BigDecimal.double_fig
250
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
237
251
  cos = (1 - x**2).sqrt(prec2)
238
252
  if cos.zero?
239
253
  PI(prec2).div(x > 0 ? 2 : -2, prec)
@@ -259,7 +273,7 @@ module BigMath
259
273
  raise Math::DomainError, "Out of domain argument for acos" if x < -1 || x > 1
260
274
  return BigDecimal::Internal.nan_computation_result if x.nan?
261
275
 
262
- prec2 = prec + BigDecimal.double_fig
276
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
263
277
  return (PI(prec2) / 2).sub(asin(x, prec2), prec) if x < 0
264
278
  return PI(prec2).div(2, prec) if x.zero?
265
279
 
@@ -282,29 +296,22 @@ module BigMath
282
296
  prec = BigDecimal::Internal.coerce_validate_prec(prec, :atan)
283
297
  x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :atan)
284
298
  return BigDecimal::Internal.nan_computation_result if x.nan?
285
- n = prec + BigDecimal.double_fig
286
- pi = PI(n)
299
+ n = prec + BigDecimal::Internal::EXTRA_PREC
300
+ return PI(n).div(2 * x.infinite?, prec) if x.infinite?
301
+
287
302
  x = -x if neg = x < 0
288
- return pi.div(neg ? -2 : 2, prec) if x.infinite?
289
- return pi.div(neg ? -4 : 4, prec) if x.round(n) == 1
290
- x = BigDecimal("1").div(x, n) if inv = x > 1
291
- x = (-1 + sqrt(1 + x.mult(x, n), n)).div(x, n) if dbl = x > 0.5
292
- y = x
293
- d = y
294
- t = x
295
- r = BigDecimal("3")
296
- x2 = x.mult(x,n)
297
- while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
298
- m = BigDecimal.double_fig if m < BigDecimal.double_fig
299
- t = -t.mult(x2,n)
300
- d = t.div(r,m)
301
- y += d
302
- r += 2
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(x.to_f), 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)
303
312
  end
304
- y *= 2 if dbl
305
- y = pi / 2 - y if inv
306
- y = -y if neg
307
- y.mult(1, prec)
313
+ y = PI(n) / 2 - y if inv
314
+ y.mult(neg ? -1 : 1, prec)
308
315
  end
309
316
 
310
317
  # call-seq:
@@ -333,7 +340,7 @@ module BigMath
333
340
 
334
341
  y = -y if neg = y < 0
335
342
  xlarge = y.abs < x.abs
336
- prec2 = prec + BigDecimal.double_fig
343
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
337
344
  if x > 0
338
345
  v = xlarge ? atan(y.div(x, prec2), prec) : PI(prec2) / 2 - atan(x.div(y, prec2), prec2)
339
346
  else
@@ -359,7 +366,7 @@ module BigMath
359
366
  return BigDecimal::Internal.nan_computation_result if x.nan?
360
367
  return BigDecimal::Internal.infinity_computation_result * x.infinite? if x.infinite?
361
368
 
362
- prec2 = prec + BigDecimal.double_fig
369
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
363
370
  prec2 -= x.exponent if x.exponent < 0
364
371
  e = exp(x, prec2)
365
372
  (e - BigDecimal(1).div(e, prec2)).div(2, prec)
@@ -382,7 +389,7 @@ module BigMath
382
389
  return BigDecimal::Internal.nan_computation_result if x.nan?
383
390
  return BigDecimal::Internal.infinity_computation_result if x.infinite?
384
391
 
385
- prec2 = prec + BigDecimal.double_fig
392
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
386
393
  e = exp(x, prec2)
387
394
  (e + BigDecimal(1).div(e, prec2)).div(2, prec)
388
395
  end
@@ -404,7 +411,7 @@ module BigMath
404
411
  return BigDecimal::Internal.nan_computation_result if x.nan?
405
412
  return BigDecimal(x.infinite?) if x.infinite?
406
413
 
407
- prec2 = prec + BigDecimal.double_fig + [-x.exponent, 0].max
414
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC + [-x.exponent, 0].max
408
415
  e = exp(x, prec2)
409
416
  einv = BigDecimal(1).div(e, prec2)
410
417
  (e - einv).div(e + einv, prec)
@@ -428,7 +435,7 @@ module BigMath
428
435
  return BigDecimal::Internal.infinity_computation_result * x.infinite? if x.infinite?
429
436
  return -asinh(-x, prec) if x < 0
430
437
 
431
- sqrt_prec = prec + [-x.exponent, 0].max + BigDecimal.double_fig
438
+ sqrt_prec = prec + [-x.exponent, 0].max + BigDecimal::Internal::EXTRA_PREC
432
439
  log(x + sqrt(x**2 + 1, sqrt_prec), prec)
433
440
  end
434
441
 
@@ -450,7 +457,7 @@ module BigMath
450
457
  return BigDecimal::Internal.infinity_computation_result if x.infinite?
451
458
  return BigDecimal::Internal.nan_computation_result if x.nan?
452
459
 
453
- log(x + sqrt(x**2 - 1, prec + BigDecimal.double_fig), prec)
460
+ log(x + sqrt(x**2 - 1, prec + BigDecimal::Internal::EXTRA_PREC), prec)
454
461
  end
455
462
 
456
463
  # call-seq:
@@ -472,7 +479,7 @@ module BigMath
472
479
  return BigDecimal::Internal.infinity_computation_result if x == 1
473
480
  return -BigDecimal::Internal.infinity_computation_result if x == -1
474
481
 
475
- prec2 = prec + BigDecimal.double_fig
482
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
476
483
  (log(x + 1, prec2) - log(1 - x, prec2)).div(2, prec)
477
484
  end
478
485
 
@@ -497,10 +504,10 @@ module BigMath
497
504
  return BigDecimal::Internal.nan_computation_result if x.nan?
498
505
  return BigDecimal::Internal.infinity_computation_result if x.infinite? == 1
499
506
 
500
- prec2 = prec + BigDecimal.double_fig * 3 / 2
507
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC * 3 / 2
501
508
  v = log(x, prec2).div(log(BigDecimal(2), prec2), prec2)
502
509
  # 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)
510
+ v = v.round(prec + BigDecimal::Internal::EXTRA_PREC - (v.exponent < 0 ? v.exponent : 0), BigDecimal::ROUND_HALF_UP)
504
511
  v.mult(1, prec)
505
512
  end
506
513
 
@@ -525,10 +532,10 @@ module BigMath
525
532
  return BigDecimal::Internal.nan_computation_result if x.nan?
526
533
  return BigDecimal::Internal.infinity_computation_result if x.infinite? == 1
527
534
 
528
- prec2 = prec + BigDecimal.double_fig * 3 / 2
535
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC * 3 / 2
529
536
  v = log(x, prec2).div(log(BigDecimal(10), prec2), prec2)
530
537
  # 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)
538
+ v = v.round(prec + BigDecimal::Internal::EXTRA_PREC - (v.exponent < 0 ? v.exponent : 0), BigDecimal::ROUND_HALF_UP)
532
539
  v.mult(1, prec)
533
540
  end
534
541
 
@@ -565,25 +572,19 @@ module BigMath
565
572
  if x < -1
566
573
  # log10(exp(x)) = x * log10(e)
567
574
  lg_e = 0.4342944819032518
568
- exp_prec = prec + (lg_e * x).ceil + BigDecimal.double_fig
575
+ exp_prec = prec + (lg_e * x).ceil + BigDecimal::Internal::EXTRA_PREC
569
576
  elsif x < 1
570
- exp_prec = prec - x.exponent + BigDecimal.double_fig
577
+ exp_prec = prec - x.exponent + BigDecimal::Internal::EXTRA_PREC
571
578
  else
572
579
  exp_prec = prec
573
580
  end
574
581
 
575
582
  return BigDecimal(-1) if exp_prec <= 0
576
583
 
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
584
+ exp(x, exp_prec).sub(1, prec)
585
585
  end
586
586
 
587
+ # call-seq:
587
588
  # erf(decimal, numeric) -> BigDecimal
588
589
  #
589
590
  # Computes the error function of +decimal+ to the specified number of digits of
@@ -608,15 +609,10 @@ module BigMath
608
609
  log10_erfc = -xf ** 2 / Math.log(10) - Math.log10(xf * Math::PI ** 0.5)
609
610
  erfc_prec = [prec + log10_erfc.ceil, 1].max
610
611
  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
612
+ return BigDecimal(1).sub(erfc, prec) if erfc
617
613
  end
618
614
 
619
- prec2 = prec + BigDecimal.double_fig
615
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
620
616
  x_smallprec = x.mult(1, Integer.sqrt(prec2) / 2)
621
617
  # Taylor series of x with small precision is fast
622
618
  erf1 = _erf_taylor(x_smallprec, BigDecimal(0), BigDecimal(0), prec2)
@@ -640,7 +636,7 @@ module BigMath
640
636
  x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :erfc)
641
637
  return BigDecimal::Internal.nan_computation_result if x.nan?
642
638
  return BigDecimal(1 - x.infinite?) if x.infinite?
643
- return BigDecimal(1).sub(erf(x, prec + BigDecimal.double_fig), prec) if x < 0
639
+ return BigDecimal(1).sub(erf(x, prec + BigDecimal::Internal::EXTRA_PREC), prec) if x < 0.5
644
640
  return BigDecimal(0) if x > 5000000000 # erfc(5000000000) < 1e-10000000000000000000 (underflow)
645
641
 
646
642
  if x >= 8
@@ -649,9 +645,10 @@ module BigMath
649
645
  end
650
646
 
651
647
  # erfc(x) = 1 - erf(x) < exp(-x**2)/x/sqrt(pi)
652
- # Precision of erf(x) needs about log10(exp(-x**2)) extra digits
648
+ # Precision of erf(x) needs about log10(exp(-x**2)/x/sqrt(pi)) extra digits
653
649
  log10 = 2.302585092994046
654
- high_prec = prec + BigDecimal.double_fig + (x.ceil**2 / log10).ceil
650
+ xf = x.to_f
651
+ high_prec = prec + BigDecimal::Internal::EXTRA_PREC + ((xf**2 + Math.log(xf) + Math.log(Math::PI)/2) / log10).ceil
655
652
  BigDecimal(1).sub(erf(x, high_prec), prec)
656
653
  end
657
654
 
@@ -700,7 +697,7 @@ module BigMath
700
697
  # Using Stirling's approximation, we can simplify this condition to:
701
698
  # sqrt(2)/2 + k*log(k) - k - 2*k*log(x) < -prec*log(10)
702
699
  # and the left side is minimized when k = x**2.
703
- prec += BigDecimal.double_fig
700
+ prec += BigDecimal::Internal::EXTRA_PREC
704
701
  xf = x.to_f
705
702
  kmax = (1..(xf ** 2).floor).bsearch do |k|
706
703
  Math.log(2) / 2 + k * Math.log(k) - k - 2 * k * Math.log(xf) < -prec * Math.log(10)
@@ -708,7 +705,8 @@ module BigMath
708
705
  return unless kmax
709
706
 
710
707
  sum = BigDecimal(1)
711
- x2 = x.mult(x, prec)
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)
712
710
  d = BigDecimal(1)
713
711
  (1..kmax).each do |k|
714
712
  d = d.div(x2, prec).mult(1 - 2 * k, prec).div(2, prec)
@@ -729,7 +727,7 @@ module BigMath
729
727
  def gamma(x, prec)
730
728
  prec = BigDecimal::Internal.coerce_validate_prec(prec, :gamma)
731
729
  x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :gamma)
732
- prec2 = prec + BigDecimal.double_fig
730
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
733
731
  if x < 0.5
734
732
  raise Math::DomainError, 'Numerical argument is out of domain - gamma' if x.frac.zero?
735
733
 
@@ -757,7 +755,7 @@ module BigMath
757
755
  def lgamma(x, prec)
758
756
  prec = BigDecimal::Internal.coerce_validate_prec(prec, :lgamma)
759
757
  x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :lgamma)
760
- prec2 = prec + BigDecimal.double_fig
758
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
761
759
  if x < 0.5
762
760
  return [BigDecimal::INFINITY, 1] if x.frac.zero?
763
761
 
@@ -766,7 +764,7 @@ module BigMath
766
764
  pi = PI(prec2)
767
765
  sin = _sinpix(x, pi, prec2)
768
766
  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
767
+ return [log_gamma, sin > 0 ? 1 : -1] if prec2 + log_gamma.exponent > prec + BigDecimal::Internal::EXTRA_PREC
770
768
 
771
769
  # Retry with higher precision if loss of significance is too large
772
770
  prec2 = prec2 * 3 / 2
@@ -816,7 +814,7 @@ module BigMath
816
814
  loggamma_k = 0
817
815
  ck_exponents = (1..a-1).map do |k|
818
816
  loggamma_k += Math.log10(k - 1) if k > 1
819
- -loggamma_k - k / log10f + (k - 0.5) * Math.log10(a - k) - BigMath.log10(x_low_prec.add(k, low_prec), low_prec)
817
+ -loggamma_k - k / log10f + (k - 0.5) * Math.log10(a - k) - BigDecimal::Internal.float_log(x_low_prec.add(k, low_prec)) / log10f
820
818
  end
821
819
 
822
820
  # Estimate exponent of sum by Stirling's approximation
@@ -897,39 +895,20 @@ module BigMath
897
895
  # #=> "0.31415926535897932384626433832795e1"
898
896
  #
899
897
  def PI(prec)
898
+ # Gauss–Legendre algorithm
900
899
  prec = BigDecimal::Internal.coerce_validate_prec(prec, :PI)
901
- n = prec + BigDecimal.double_fig
902
- zero = BigDecimal("0")
903
- one = BigDecimal("1")
904
- two = BigDecimal("2")
905
-
906
- m25 = BigDecimal("-0.04")
907
- m57121 = BigDecimal("-57121")
908
-
909
- pi = zero
910
-
911
- d = one
912
- k = one
913
- t = BigDecimal("-80")
914
- while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
915
- m = BigDecimal.double_fig if m < BigDecimal.double_fig
916
- t = t*m25
917
- d = t.div(k,m)
918
- k = k+two
919
- pi = pi + d
920
- end
921
-
922
- d = one
923
- k = one
924
- t = BigDecimal("956")
925
- while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
926
- m = BigDecimal.double_fig if m < BigDecimal.double_fig
927
- t = t.div(m57121,n)
928
- d = t.div(k,m)
929
- pi = pi + d
930
- k = k+two
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
931
910
  end
932
- pi.mult(1, prec)
911
+ (a * b).div(s, prec)
933
912
  end
934
913
 
935
914
  # call-seq:
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  #
3
3
  #--
4
4
  # bigdecimal/util extends various native classes to provide the #to_d method,