#!/usr/bin/perl -w
# http://www.cyut.edu.tw/~ckhung/
# 從命令列上讀入 prec, 計算 pi=3.1416 ... 精準至小數以下 prec 位.

# 選項:
# -p prec	指定精準度
# -v		verbose, 過程中多印一些訊息

# 演算法: 利用 pi ~= 2^k * sin (pi / 2^k) 所導出的遞迴關係式:
#     pi(k+1) = pi(k) / cos(pi / 2^(k+1))
#     cos(th/2) = sqrt((1 + cos(th) / 2)
# 來計算 pi. (想像單位圓內接正 2^k * 6 邊形)
# 每次運算約增加 2 個 bit 的精準度, 故迴圈要執行 prec * 10 / 3 / 2 次

use Getopt::Std;
use Math::BigFloat;

my (
    %opts,		# 命令列選項
    $prec,		# 精確到小數下幾位?
    $p,			# pi 的近似值
    $c,			# 正多邊形的 "一頁" (很窄) 的內角 cos 值
    $i,
);

getopts('vp:', \%opts);

$prec = $opts{p} || 60;
Math::BigFloat::div_scale($prec);
# 也可以直接去修改一個全域變數: (不建議這麼做)
# $Math::BigFloat::div_scale = $prec;

$p = Math::BigFloat->new("3");
$c = Math::BigFloat->new("0.5");
$c = (($c + 1) / 2)->bsqrt();
## 上句其實是簡寫. 原來比較麻煩的寫法如下, 反而還不能執行):
# $c = Math::BigFloat::bsqrt(
#    Math::BigFloat::fdiv( Math::BigFloat::fadd($c, 1), 2)
# );
for ($i=1; $i<=$prec/3*5; ++$i) {
    printf "%3d: %s\n", $i, substr($p, 0, $prec+2) if $opts{v};
    $c = (($c + 1) / 2)->bsqrt();
#    $c = Math::BigFloat::bsqrt(($c + 1) / 2);	# 一樣的意思, 但無 inheritance
    $p = $p / $c;
}
printf "%s\n", substr($p, 0, $prec+2);
