Skip to content

Commit d493a4f

Browse files
committed
Implement BigMath::PI with Gauss-Legendre algorithm
It's fast and simple. If we improve sin/cos with bitburst algorithm, PI will be the bottleneck. Requires multiplication cost to be less than O(n^2).
1 parent 0240a43 commit d493a4f

File tree

2 files changed

+13
-32
lines changed

2 files changed

+13
-32
lines changed

lib/bigdecimal/math.rb

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -885,39 +885,20 @@ def ldexp(x, exponent)
885885
# #=> "0.31415926535897932384626433832795e1"
886886
#
887887
def PI(prec)
888+
# Gauss–Legendre algorithm
888889
prec = BigDecimal::Internal.coerce_validate_prec(prec, :PI)
889-
n = prec + BigDecimal.double_fig
890-
zero = BigDecimal("0")
891-
one = BigDecimal("1")
892-
two = BigDecimal("2")
893-
894-
m25 = BigDecimal("-0.04")
895-
m57121 = BigDecimal("-57121")
896-
897-
pi = zero
898-
899-
d = one
900-
k = one
901-
t = BigDecimal("-80")
902-
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
903-
m = BigDecimal.double_fig if m < BigDecimal.double_fig
904-
t = t*m25
905-
d = t.div(k,m)
906-
k = k+two
907-
pi = pi + d
908-
end
909-
910-
d = one
911-
k = one
912-
t = BigDecimal("956")
913-
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
914-
m = BigDecimal.double_fig if m < BigDecimal.double_fig
915-
t = t.div(m57121,n)
916-
d = t.div(k,m)
917-
pi = pi + d
918-
k = k+two
890+
n = prec + BigDecimal.double_fig
891+
a = BigDecimal(1)
892+
b = BigDecimal(0.5, 0).sqrt(n)
893+
s = BigDecimal(0.25, 0)
894+
t = 1
895+
while a != b && (a - b).exponent > 1 - n
896+
c = (a - b).div(2, n)
897+
a, b = (a + b).div(2, n), (a * b).sqrt(n)
898+
s = s.sub(c * c * t, n)
899+
t *= 2
919900
end
920-
pi.mult(1, prec)
901+
(a * b).div(s, prec)
921902
end
922903

923904
# call-seq:

sample/pi.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# pi.rb
33
#
44
# Calculates 3.1415.... (the number of times that a circle's diameter
5-
# will fit around the circle) using J. Machin's formula.
5+
# will fit around the circle)
66
#
77

88
require "bigdecimal"

0 commit comments

Comments
 (0)