導入
こんにちは、もんすんです。
プログラミングでは、金銭計算を行う場面がよくありますよね??
しかし、浮動小数点型(float
や double
)を使った金銭計算には注意が必要です。
浮動小数点型と文字を見て、ドキッとした方、少なくはないはずです。
今回は、浮動小数点型の問題と、その解決方法についてわかりやすく解説します。
浮動小数点型について
なぜ浮動小数点型が金銭計算に向かないのか?
float
や double
は、科学計算や工学計算のために設計されたデータ型です。
それらは非常に大きな範囲の数値を効率的に扱えますが、正確に小数を表現できない場合があります。
例えば、次のコードを実行してみましょう。
public class MoneyCalculation {
public static void main(String[] args) {
System.out.println(1.03 - 0.42); // 結果: 0.6100000000000001
System.out.println(1.00 - 0.90); // 結果: 0.09999999999999998
}
}
コメントアウトにも示していますが、それぞれ 0.61 と 0.10 となってい欲しいところ、表示される結果は少しずれています。
これは、浮動小数点型が内部で数値を2進数として扱うため、10進数の小数を正確に表現できないからです。
例えば、0.1や0.3などは2進数で無限に続く小数になるため、丸め誤差が生じます。
2進数の場合、0.1は0.00011001100110011... (繰り返し)
となり、0.3は0.01001100110011... (繰り返し)
となります。
その結果、浮動小数点型を使った計算では、期待通りの結果が得られず、誤差が蓄積することがあります。
こういった誤差が、正確な計算が求められる金融関連、つまり金銭計算に大きな影響を与えてしまうのです。
金銭計算の正しい方法
では、正しい金銭計算はどうやって実現すればいいのでしょうか?
正確な金銭計算を行うためには、以下の方法を検討しましょう。
1. BigDecimal
を使う
BigDecimal
は高精度な数値計算をサポートするクラスです。
10進数の固定小数点形式で数値を表現してくれます。
つまり、演算は10進数ベースで行われるため、2進数特有の丸め誤差が発生しません。
BigDecimal
は、以下のように使用します。
import java.math.BigDecimal;
public class MoneyCalculation {
public static void main(String[] args) {
BigDecimal funds = new BigDecimal("1.00");
BigDecimal price = new BigDecimal("0.10");
int itemsBought = 0;
while (funds.compareTo(price) >= 0) {
funds = funds.subtract(price);
itemsBought++;
}
System.out.println(itemsBought + "個の商品を購入しました。");
System.out.println("残金: $" + funds);
}
}
出力:
10個の商品を購入しました。
残金: $0.00
この方法により、浮動小数点型の誤差がなくなり、正確な結果が得られます。
2. 整数型(int
や long
)を使う
金額をドルや円ではなく、セントや最小単位で管理する方法です。
この方法は処理が高速でシンプルです。
public class MoneyCalculation {
public static void main(String[] args) {
int funds = 100; // 1ドルをセントで表現
int price = 10; // 1個10セント
int itemsBought = 0;
while (funds >= price) {
funds -= price;
itemsBought++;
}
System.out.println(itemsBought + "個の商品を購入しました。");
System.out.println("残金: " + funds + "セント");
}
}
出力:
10個の商品を購入しました。
残金: 0セント
整数型を使う場合は、計算前後に単位(ドル→セント)を意識する必要がありますが、精度が高く計算も高速です。
どの方法を選ぶべきか?
-
BigDecimal
- メリット: 高精度、丸め制御が可能
- デメリット: 記述が煩雑で、計算がやや遅い
- 適用例: 金融計算やビジネスロジック
-
整数型(
int
やlong
)- メリット: シンプルで高速
-
デメリット: 桁数制限がある(
int
で約9桁、long
で約18桁) - 適用例: 小規模な金額計算や性能が重視される場合
最後に
今回紹介したように、浮動小数点型(float
や double
)は、金銭計算には向いていません。
正確さが必要な場合は、BigDecimal
を使うか、整数型で金額を最小単位に変換して計算しましょう!