Skip to content

Instantly share code, notes, and snippets.

@komasaru
Last active April 19, 2018 05:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save komasaru/a5639355b3b37302a970 to your computer and use it in GitHub Desktop.
Save komasaru/a5639355b3b37302a970 to your computer and use it in GitHub Desktop.
Ruby script to compute pi by Chudnovsky formula and Binary Splitting Algorithm using GMP libarary.
#!/usr/local/bin/ruby
#**************************************************************
# Computing pi by Binary Splitting Algorithm with GMP libarary.
#**************************************************************
require 'gmp'
class Chudnovsky
# Constants
A = 13591409
B = 545140134
C = 640320
D = 426880
E = 10005
DIGITS_PER_TERM = Math.log(53360 ** 3) / Math.log(10) # = 14.1816474627254776555
def initialize(digits)
@digits = digits
@c3_24 = C ** 3 / 24
@n = ((@digits + 1) / DIGITS_PER_TERM).truncate # Somehow, need to add 1 to digits.
@prec = ((@digits + 1) * Math.log2(10)).truncate # Somehow, need to add 1 to digits.
end
# Compute PI
def comp_pi
puts "**** PI Computation ( #{@digits} digits )"
begin
# Compute Pi
pqt = comp_pqt(0, @n)
pi = GMP.F(D)
pi *= GMP.F(E, @prec).sqrt
pi *= pqt[:q]
pi /= A * pqt[:q] + pqt[:t]
# Output
File.open("pi.txt", "w") { |f| f.puts pi }
rescue => e
raise
end
end
private
# Compute PQT (by Binary Splitting Algorith)
def comp_pqt(n1, n2)
pqt = Hash.new
begin
if n1 + 1 == n2
pqt[:p] = GMP.Z(2 * n2 - 1)
pqt[:p] *= GMP.Z(6 * n2 - 1)
pqt[:p] *= GMP.Z(6 * n2 - 5)
pqt[:q] = GMP.Z(@c3_24 * n2 * n2 * n2)
pqt[:t] = GMP.Z((A + B * n2) * pqt[:p])
pqt[:t] = pqt[:t].neg if (n2 & 1) == 1
else
m = (n1 + n2) / 2
res1 = comp_pqt(n1, m)
res2 = comp_pqt(m, n2)
pqt[:p] = res1[:p] * res2[:p]
pqt[:q] = res1[:q] * res2[:q]
pqt[:t] = res1[:t] * res2[:q]+ res1[:p] * res2[:t]
end
return pqt
rescue => e
raise
end
end
end
if __FILE__ ==$0
begin
digits = ARGV[0] ? ARGV[0].to_i : 100
obj = Chudnovsky.new(digits)
res = Benchmark.realtime { obj.comp_pi }
puts "( TIME: #{res} seconds )"
rescue => e
puts "[#{e.class}] #{e.message}\n"
e.backtrace.each{ |tr| puts "\t#{tr}" }
exit 1
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment