Skip to content

Commit 3862e99

Browse files
committed
Implement BigMath::PI with Gauss-Legendre algorithm
It's fast and simple. Requires multiplication cost to be less than O(n^2).
1 parent 84646b8 commit 3862e99

1 file changed

Lines changed: 12 additions & 31 deletions

File tree

lib/bigdecimal/math.rb

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -579,39 +579,20 @@ def expm1(x, prec)
579579
# #=> "0.31415926535897932384626433832795e1"
580580
#
581581
def PI(prec)
582+
# Gauss–Legendre algorithm
582583
prec = BigDecimal::Internal.coerce_validate_prec(prec, :PI)
583-
n = prec + BigDecimal.double_fig
584-
zero = BigDecimal("0")
585-
one = BigDecimal("1")
586-
two = BigDecimal("2")
587-
588-
m25 = BigDecimal("-0.04")
589-
m57121 = BigDecimal("-57121")
590-
591-
pi = zero
592-
593-
d = one
594-
k = one
595-
t = BigDecimal("-80")
596-
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
597-
m = BigDecimal.double_fig if m < BigDecimal.double_fig
598-
t = t*m25
599-
d = t.div(k,m)
600-
k = k+two
601-
pi = pi + d
602-
end
603-
604-
d = one
605-
k = one
606-
t = BigDecimal("956")
607-
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
608-
m = BigDecimal.double_fig if m < BigDecimal.double_fig
609-
t = t.div(m57121,n)
610-
d = t.div(k,m)
611-
pi = pi + d
612-
k = k+two
584+
n = prec + BigDecimal.double_fig
585+
a = BigDecimal(1)
586+
b = BigDecimal(0.5, 0).sqrt(n)
587+
s = BigDecimal(0.25, 0)
588+
t = 1
589+
while a != b && (a - b).exponent > 1 - n
590+
c = (a - b).div(2, n)
591+
a, b = (a + b).div(2, n), (a * b).sqrt(n)
592+
s = s.sub(c * c * t, n)
593+
t *= 2
613594
end
614-
pi.mult(1, prec)
595+
(a * b).div(s, prec)
615596
end
616597

617598
# call-seq:

0 commit comments

Comments
 (0)