Skip to content

Commit 52848d1

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 d93b542 commit 52848d1

File tree

1 file changed

+12
-31
lines changed

1 file changed

+12
-31
lines changed

lib/bigdecimal/math.rb

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -198,39 +198,20 @@ def atan(x, prec)
198198
# #=> "0.31415926535897932384626433832795e1"
199199
#
200200
def PI(prec)
201+
# Gauss–Legendre algorithm
201202
BigDecimal::Internal.validate_prec(prec, :PI)
202-
n = prec + BigDecimal.double_fig
203-
zero = BigDecimal("0")
204-
one = BigDecimal("1")
205-
two = BigDecimal("2")
206-
207-
m25 = BigDecimal("-0.04")
208-
m57121 = BigDecimal("-57121")
209-
210-
pi = zero
211-
212-
d = one
213-
k = one
214-
t = BigDecimal("-80")
215-
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
216-
m = BigDecimal.double_fig if m < BigDecimal.double_fig
217-
t = t*m25
218-
d = t.div(k,m)
219-
k = k+two
220-
pi = pi + d
221-
end
222-
223-
d = one
224-
k = one
225-
t = BigDecimal("956")
226-
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
227-
m = BigDecimal.double_fig if m < BigDecimal.double_fig
228-
t = t.div(m57121,n)
229-
d = t.div(k,m)
230-
pi = pi + d
231-
k = k+two
203+
n = prec + BigDecimal.double_fig
204+
a = BigDecimal(1)
205+
b = BigDecimal(0.5, 0).sqrt(n)
206+
s = BigDecimal(0.25, 0)
207+
t = 1
208+
while a != b && (a - b).exponent > 1 - n
209+
c = (a - b).div(2, n)
210+
a, b = (a + b).div(2, n), (a * b).sqrt(n)
211+
s = s.sub(c * c * t, n)
212+
t *= 2
232213
end
233-
pi.mult(1, prec)
214+
(a * b).div(s, prec)
234215
end
235216

236217
# call-seq:

0 commit comments

Comments
 (0)