メジャーな数学関数を自力計算する

三角関数や対数などの近似計算の方法を短い Ruby コードでご紹介。だいたいマクローリン展開です。

子供のころ何気なく sin とか log とか使っていて、ふと「コンピュータはどうやってこの値を計算してるんだろう」と思ったものです。そんな昔の自分に見せてあげたいエントリ。と言っても、今時のコンピュータは FPU 持ってるんでこんな計算してませんが。

なお、ちゃんとテストしてません。

三角関数

0 に近い方が精度高いです。99 とか 98 とかは適当に大きな数字。

def sin(x)
  r, f = 0, 1
  1.step(99, 2) do |i|
    r += x ** i / f
    f *= -(i+1)*(i+2)
  end
  r
end
def cos(x)
  r, f = 0, 1
  0.step(98, 2) do |i|
    r += x ** i / f
    f *= -(i+1)*(i+2)
  end
  r
end
def tan(x)
  sin(x) / cos(x)
end

指数関数

def exp(x)
  v = t = f = 1.0
  99.times do |i|
    t *= x / (i+1)
    v += t
  end
  v
end

自然対数

マクローリン展開だと収束が遅すぎるので、log(x) = 2 artanh ( (x-1)/(x+1) ) の式で。それでも x が大きいと収束が遅い。

def log(x)
  v = t = e = (x - 1.0) / (x + 1.0)
  999.times do |i|
    t *= e * e
    v += t / (i + 1.5)
  end
  v
end

べき乗

def pow(x, y)
  exp(log(x) * y)
end

補足: アルゴリズムの選定基準

  • 簡潔さ最優先
  • 収束の速さは多少気にする
  • 定数オーダの実行速度は気にしない

もっといい方法があったら教えてください。