2008年8月9日土曜日

複利の計算

リボ払い

ちょうど「ブログが続かないわけ | リボ払いは悪魔」を読んでいて、「リボ払いは使うな! 気をつけろ」ということを、いつどこで教えてもらったのかと記憶の糸を辿りつつ、そういえば「複利の計算」ってどうやるだっけ (?) と疑問が。 (@_@;) 複利の計算方法、学生時代に習ったっけ?全く記憶がない。どこで耳にしたのか、雪だるま式に何かがどうかなるというイメージがあるだけ。恥ずかしながら具体的な意味を知らず。 ^^;

 

複利

複利 – Wikipedia によると、

複利(ふくり)とは、複利法によって計算された利子のことで、利子元金に組み入れる方式で利子に利子がつくことを言う。(…)

 投資などでは得た利子を元本に組み入れることにより、元本を増やすことで次に受け取る利子が増える事になり雪だるま式に利子が増えていくことになる。

雪だるま式というイメージはどうやら見当違いではなかったようだ。つまるところ、利子を計算するための元になるお金 (元金) があったときに、そのお金に対してだけ利子を考えていくのではなく、「元金に利子を足したもの」に対して利子を考え、それ繰り返していくということ。

複利は、投資の場合に有効に働けば大きな利益を得られるが、逆に借金した場合に大きな力として働いてしまったら恐しいことに。Airblog: 複利とアインシュタイン によると、

The most powerful force in the universe is compound interest.(wikiquote)

といったのは物理学者のアインシュタイン。曰く、「世界でもっとも強い力(=force)は、複利だ」。身近な例でいうと、住宅ローン。

compound interest の意味は、

interest は、「興味、関心;関心事」のほか「利子、利息;利率」や「利益;私利私欲」という意味で用いられる。
compound は、「複数の部分(要素)からなる、合成の、混成の、複合の」という意味。

(ぱふぅ家のホームページcompound interest より)

 

具体的な複利の計算

「複数」という言葉に対して「単数」があるように、「複利」に対して「単利」がある。この違いについて具体的に例を挙げて説明してあった 大学生の株日記単利と複利 がわかりやすかった。

100万円の元本があるとします。1年の利回りが20%とします。
1年で 100万円×0.2=20万円の利子がついて、合計で120万円となります。
2年目は その120万に対して20%の利子がつくので
120万円×0.2=24万円の利子がつき、合計で144万円となります。 (…)

注目するところは、2 年目の計算のところで、”1 年目の利子がついた金額に対して利子を計算している” こと。これが雪だるまになるしかけのようだ。

 

計算式

3分LifeHacking:複利計算を“暗算”で行う - ITmedia Biz.ID によると、

数式で考えると、利率をr、年数をNとした場合、資産の増加は、

  • A(1+r)^N

いきなり数式がでてきたが、具体的に考えてみる。 上記の例に当てはめると、

1 年目 : 100 * (1 + 0.2)

2 年目 : (100 * (1 + 0.2)) * (1 + 0.2) = 100 * (1 + 0.2) ^ 2

3 年目 : ((100 * (1 + 0.2)) * (1 + 0.2)) * (1 + 0.2) = 100 * (1 + 0.2) ^ 3

n 年目 : 100 * (1 + 0.2) ^ n

元本を A 、利率を r 、年数を N とすれば、

1 年目 : A * (1 + r)

2 年目 : (A * (1 + r)) * (1 + r) = A * (1 + r) ^ 2

3 年目 : ((A * (1 + r)) * (1 + r)) * (1 + r) = A * (1 + r) ^ 3

N 年目 : A (1 + r) ^ N

この計算式を使うならば、上例の 10 年目を 100(1+0.2)^10 - Google 検索 で求めることができる。

 

再帰で表現

再び、大学生の株日記単利と複利 の例として挙げられていた例を見てみる。

100万円の元本があるとします。1年の利回りが20%とします。

http://daigakusei.daa.jp/money/tanrifukuri.html

単利と複利 via kwout

上の表の「はじめから 10 年目」までの値をリストとして眺めていると、このまま延々と続く「無限リスト」を想起する。無限リストと言えば、思い出すのは Haskell …

先ほどの複利の計算方法は忘れて、複利の定義に戻り具体例で考えると、

1 年目の値は、はじめの値 の 1.2 倍

2 年目の値は、1 年目の値の 1.2 倍

3 年目の値は、2 年目の値の 1.2 倍

N 年目の値は、(N – 1) 年目の値の 1.2 倍

となり、再帰的な表現がされていることがわかる。 (再帰については「ループと再帰」を参照。)

 

Haskell で実装

早速これを Haskell で実装してみる。

fukuri gankin riritu = [gankin] ++ fukuri(gankin*(1+riritu)) riritu

main = print $ map round $ take 11 $ fukuri 100 0.2

fukuri 関数に元金と利率を適用すると、元金を先頭にした無限リストが生成される。それに take 関数を適用して必要なだけ取り出す。

 

Ruby で実装

Ruby で書いてみると、

def fukuri(gankin,riritu,n)
  return gankin if n == 0
  return fukuri(gankin*(1+riritu),riritu,n-1)
end

puts fukuri(100,0.2,10)

fukuri 関数の引数は、元金と利率と、利率を年利と考えるならば n 年目の金額を求めるための n を渡す。上記では、元金 100, 利率(年利を仮定し) 20% で 10 年目の金額を求めている。

今はたまたま年利として考えたが、金利は長さによって呼び方が異なり、金利ってどういうもの? - レジャー王を目指して によると、

金利の単位 日歩(ひぶ) 月利(げつり) 年利(ねんり)

1日の利息 1ヶ月の利息の割合 1年間の利息の割合

年利29.2%の場合 0.08% 2.43% 29.2%

この数字は、単純に、年利÷12=月利 年利÷365=日歩という計算方法になります。

という関係がある。

 

ところで、上記の関数は特定の値を求めるものだったが、これを Haskell のリストのように元金を先頭した配列を取得しようとするなら、

def fukuri2(gankin,riritu,n)
  return [] if n == 0
  return [gankin.round] + fukuri2(gankin*(1+riritu),riritu,n-1)
end

p fukuri2(100,0.2,11)

 

考え方

ところで、 tnomuraのブログ : 思考と再帰 には Scheme による実装が書かれている。

複利の考え方を言葉で説明すると次のようになる。
1.ローンをすぐに返済すれば利子はなく、元金のままだ。
2.1年後の期末の元利合計は、期首の元利合計を元金と考えそれに利率をかけた利子と期首の元利合計(その年度の元金)との和になる。

これをSchemeでプログラムすると次のようになる。
(define (ganri gankin riritu kikan)
  (if (= kikan 0)
      gankin
      (* (ganri gankin riritu (- kikan 1)) (+ 1 riritu))))
> (ganri 100 0.02 10)
121.89944199947573

ほぼ、文章で説明した通りの内容だ。同じパターンの操作を繰り返すという内容をプログラムするのに再帰を用いると、思考の内容をほぼそのままプログラムとして実行することができるのだ。再帰で表現された繰り返しは、手続き言語の構文のループで表現するよりも、脳の中の思考の形態により近いような気がする

(太字は引用者による)

再帰になかなか慣れない自分にとって、やはり再帰はまだまだ思考内容を素直に表現できると感じるには遠いなぁ。 ^^;

自分の場合は、次のように考えた方が自然に感じる。まず、「複利」というモヤモヤとした実体をイメージする。そこに「元金」と「利率」を設定。next の呼出しを行うと、「複利」は元金と利率を元に元金を設定する。これを next の呼出しの度に行う。

080809-003

上記を Ruby で実装すると、

class Fukuri
  def initialize(gankin,riritu)
    @gankin, @riritu = gankin, riritu
  end
  def next(n)
    n.times{@gankin = @gankin * (1+@riritu)}
  end
  def result
    return @gankin.round
  end
end

f = Fukuri.new(100,0.2)
f.next(10)
puts f.result

もし元金からのリストを得たい場合は、next の計算の度に結果を保持する配列を用意しておき記録する。

再帰で表現したときに比べると、随分長くなってしまったが、こちらの方が動作をイメージしやすくて好み... ^^;