Last active
April 19, 2018 05:01
-
-
Save komasaru/5243832 to your computer and use it in GitHub Desktop.
Ruby script to calc pi by Klingenstierna formula.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/local/bin/ruby | |
#********************************************* | |
# 円周率計算 by Klingenstierna の公式 | |
#********************************************* | |
# | |
class CalcPiKlingenstierna | |
FNAME = "pi_klingenstierna.txt" | |
def initialize(x) | |
@l = x # 計算桁数 | |
@l1 = (@l / 8) + 1 # 配列サイズ | |
@n = (@l + 1) / 2 + 1 # 計算項数 | |
end | |
# 計算・結果出力 | |
def calc | |
# 計算開始時刻 | |
t0 = Time.now | |
# 配列宣言・初期化 | |
s = Array.new(@l1 + 2, 0) # 総和 | |
a = Array.new(@l1 + 2, 0) # Klingenstierna の公式の第1項 | |
b = Array.new(@l1 + 2, 0) # Klingenstierna の公式の第2項 | |
c = Array.new(@l1 + 2, 0) # Klingenstierna の公式の第3項 | |
q = Array.new(@l1 + 2, 0) # Klingenstierna の公式の第1項+第2項+第3項 | |
# Klingenstierna の公式 | |
a[0] = 32 * 10 | |
b[0] = 4 * 239 | |
c[0] = 16 * 515 | |
1.upto(@n) do |k| | |
a = long_div(a, 10 * 10) | |
b = long_div(b, 239 * 239) | |
c = long_div(c, 515 * 515) | |
q = long_sub(a, b) | |
q = long_sub(q, c) | |
q = long_div(q, 2 * k - 1) | |
unless k % 2 == 0 | |
s = long_add(s, q) | |
else | |
s = long_sub(s, q) | |
end | |
end | |
# 計算終了時刻 | |
t1 = Time.now | |
# 計算時間 | |
tt = t1 - t0 | |
# 結果出力 | |
display(tt, s) | |
rescue => e | |
raise | |
end | |
private | |
# ロング + ロング | |
def long_add(a, b) | |
z = Array.new(@n, 0) | |
cr = 0 | |
(@l1 + 1).downto(0) do |i| | |
z[i] = a[i] + b[i] + cr | |
if z[i] < 100000000 | |
cr = 0 | |
else | |
z[i] -= 100000000 | |
cr = 1 | |
end | |
end | |
return z | |
rescue => e | |
raise | |
end | |
# ロング - ロング | |
def long_sub(a, b) | |
z = Array.new(@n, 0) | |
br = 0 | |
(@l1 + 1).downto(0) do |i| | |
z[i] = a[i] - b[i] - br | |
if z[i] >= 0 | |
br = 0 | |
else | |
z[i] += 100000000 | |
br = 1 | |
end | |
end | |
return z | |
rescue => e | |
raise | |
end | |
# ロング / ショート | |
def long_div(a, b) | |
z = Array.new(@n, 0) | |
r = 0 | |
0.upto(@l1 + 1) do |i| | |
w = a[i] | |
z[i] = (w + r) / b | |
r = ((w + r) % b) * 100000000 | |
end | |
return z | |
rescue => e | |
raise | |
end | |
# 結果出力 | |
def display(tt, s) | |
puts "** Pi Computation with the Klingenstierna formula method **" | |
printf(" Digits = %d.\n", @l) | |
printf(" Time = %f seconds\n", tt) | |
# ファイル出力 | |
out_file = File.open(FNAME, "w") | |
out_file.puts "** Pi Computation with the Klingenstierna formula method **" | |
out_file.printf(" Digits = %d.\n", @l) | |
out_file.printf(" Time = %f seconds.\n\n", tt) | |
out_file.printf(" %d.\n", s[0]) | |
1.upto(@l1 - 1) do |i| | |
out_file.printf("%08d:", (i - 1) * 8 + 1) if (i % 10 == 1) | |
out_file.printf(" %08d", s[i]) | |
out_file.printf("\n") if (i % 10 == 0) | |
end | |
printf("\n") | |
rescue => e | |
raise | |
end | |
end | |
if __FILE__ == $0 | |
begin | |
print "Please input number of Pi Decimal-Digits : " | |
n = gets.to_i | |
# 計算クラスインスタンス化 | |
obj = CalcPiKlingenstierna.new(n) | |
# 円周率計算 | |
obj.calc | |
rescue => e | |
$stderr.puts "[#{e.class}] #{e.message}\n" | |
e.backtrace.each{ |tr| $stderr.puts "\t#{tr}" } | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment