ローン返済シミュレーションの作り方

# はじめに
この記事では、

* 住宅ローンなどのローン返済額の[計算式](#ローン返済シミュレーションの作り方)を紹介します。
* ローン返済額の計算をD言語で[実装](#ソースコード)します。
* D言語での実装に必要な文字列数値変換について説明します。

# 文字列→数値変換

## その１ toを使う
`std.conv`の標準ライブラリの`to`を使います。
`to!(変換後の型)(変換したい変数)`という風に使います。
`(変換後の型)`のカッコ`()`は省略可能です。

```d:sample1.d
import std.stdio, std.conv;

void main()
{
  string s1 = "42";
  int    i  = to!(int)(s1);
  writefln("%d",i);  // 42

  string s2 = "7.5";
  double d  = to!(double)(s2);
  writefln("%.2f",d); // 7.50
}
```

## その２ C言語っぽく使う
あえて、C言語っぽく実装したい場合、関数`atoi`,`atof`も用意されています。（標準ライブラリ`core.stdc.stdlib`）
`writefln`の代わりに`printf`も使えますので、あわせて紹介します。（標準ライブラリ`core.stdc.stdio`）

```d:sample2.d
import core.stdc.stdio, core.stdc.stdlib;

void main()
{
  string s1 = "42";
  int    i  = atoi(s1.ptr);
  printf("%d\n",i);  // 42

  string s2 = "7.5";
  double d  = atof(s2.ptr);
  printf("%.2f\n",d); // 7.50
}
```

# 数値→文字列変換
## その１ toを使う
数値から文字列への変換でも`std.conv`の標準ライブラリ`to`が使えます。
`std.format`の標準ライブラリ`format`を使うと文字列の書式を整形できます。

```d:sample3.d
import std.stdio, std.conv, std.format;

void main()
{
  int    i  = 42;
  string s1 = to!(string)(i);
  writeln(s1);  // 42

  double d  = 7.5;
  string s2 = to!(string)(d);
  writeln(s2); // 7.5
  string s3 = format("%.2f",d);
  writeln(s3); // 7.50
}
```

## その２ C言語っぽく使う
こちらも、C言語っぽく使えるよう関数`sprintf`が用意されています。（標準ライブラリ`core.stdc.stdio`）

```d:sample4.d
import core.stdc.stdio;

void main()
{
  char[10] c;
  int i  = 42;
  sprintf(c.ptr,"%d",i);
  printf("%s\n",c.ptr);  // 42

  double d = 7.5;
  sprintf(c.ptr,"%.2f",d);
  printf("%s\n",c.ptr); // 7.50
}
```

# ローン返済シミュレーションの作り方
文字列数値変換の使用例として、ローン返済シミュレータを作ります。

## シミュレータの仕様

* 元利均等返済
* ボーナス併用払いも計算可能
* ボーナス返済は、6ヵ月ごと年2回
* 借入時からボーナス月までの期間を6ヵ月として計算
* 返済期間が6で割り切れない場合は、最終月をボーナス月として加算
* 端数の扱いなどで実際の返済金額と異なる場合があります

## 月額返済額の計算方法
なぜ、以下の計算式になるのか興味がある方は、下の参考リンクをたどってください。

$ \mbox{[毎月返済額]} = \frac{\mbox{[借入金額]}\times\mbox{[月利]}\times(1+\mbox{[月利]})^{\mbox{[返済回数]}}}{(1+\mbox{[月利]})^{\mbox{[返済回数]-1}}} $

$ \mbox{[月利]} = \mbox{[年利]} \div 12 $

## ボーナス返済額の計算方法
月額返済額と似たような計算式になります。

$ \mbox{[ボーナス月加算額]} = \frac{\mbox{[ボーナス返済額]}\times\mbox{[金利]}\times(1+\mbox{[金利]})^{\mbox{[返済回数]}}}{(1+\mbox{[金利]})^{\mbox{[返済回数]-1}}} $

$ \mbox{[金利]} = \mbox{[年利]} \div 2 \mbox{（6か月分の金利）} $
$ \mbox{[返済回数]} = \mbox{[返済期間]} \div 6 $

# ソースコード
```d:loansim.d
// ローン返済シミュレーション
// * 元利均等返済
// * ボーナス併用払いも計算可能
import std.stdio, std.conv;

void main(string[] args)
{
	if ( args.length < 5 ){
		writeln("パラメータが必要です：[借入金額][ボーナス返済額][年利][返済回数]");
		return;
	}
	double a  = to!double(args[1]); // 借入金額
	double b  = to!double(args[2]); // aのうち、ボーナス返済額
	double r  = to!double(args[3]); // 年利
	double na = to!double(args[4]); // 返済期間
	double nb = na / 6.0;           // ボーナス返済回数
	
	writefln("借入金額         = %11,3.0f", a);
	writefln("(ボーナス返済額  = %11,3.0f)", b);
	writefln("年利             = %10.2f%%", r);
	
	a -= b;                          // ボーナスでの返済額を除く
	double ra = r / 12.0 / 100.0;    // 月利
	double rb = r /  2.0 / 100.0;    // 6か月分の金利
	
	int ma = to!int(a * ra * (1+ra) ^^ na / ((1+ra) ^^ na - 1));
	int mb = to!int(b * rb * (1+rb) ^^ nb / ((1+rb) ^^ nb - 1));
	int mt = to!int(ma * na + mb * nb);
	int me = to!int(mt - (ma * to!int(na) + mb * to!int(na / 6)));
	
	writefln("毎月返済額       = %11,3d", ma);
	writefln("ボーナス月加算額 = %11,3d", mb);
	writefln("最終月加算額     = %11,3d", me);
	writefln("返済総額         = %11,3d", mt);
}
```

## コンパイル、実行例
![prompt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675901/79693a3a-beb3-14ab-da93-5433345882c7.png)


# 参考
[いろいろなプログラミング言語での文字列数値変換](https://www.techscore.com/blog/2019/12/20/converting-between-numbers-and-strings-2019/)
[Goでの文字列数値変換](https://qiita.com/quicksort/items/c9522793a941edf074fd)
[Rustでの文字列数値変換](https://qiita.com/smicle/items/29a4d5d1d14ad7f77f60)
[ローン金利の計算法](https://style.nikkei.com/article/DGXNASFK2103W_R20C12A9000000/)