金額にdoubleを使わない理由
浮動小数点の精度問題を学びます
「金額にdoubleを使わない理由」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
危険なデフォルト
価格をdoubleに保存するのは自然に思えます。しかし、doubleではほとんどの小数を正確に表現できないため、金融計算を台無しにする小さな誤差が生じます。
典型的な驚き
doubleで0.1と0.2を足しても、0.3にはなりません。ごく小さな丸め誤差を含む値になります。
public class Main {
public static void main(String[] args) {
double result = 0.1 + 0.2;
System.out.println(result);
}
}なぜ起こるのか
コンピューターはdoubleを2進数で保存します。3分の1を10進数で正確に表せないのと同じように、0.1のような多くの小数は2進数で正確に表せません。
最も近い2進数の近似値が保存されるため、誤差が蓄積します。
誤差は蓄積する
1回だけ発生するごく小さな誤差は無害に見えるかもしれません。しかし、何千件もの取引をループで処理すると、差が蓄積して目に見える間違いになります。
public class Main {
public static void main(String[] args) {
double total = 0.0;
for (int i = 0; i < 10; i++) {
total += 0.1;
}
System.out.println(total);
}
}等価比較の失敗
丸め誤差があるため、計算したdoubleを==で比較すると、等しいはずなのに一致しないことがよくあります。
public class Main {
public static void main(String[] args) {
double a = 0.1 + 0.2;
double b = 0.3;
System.out.println(a == b);
}
}金額には正確さが必要
金融分野では、1セント未満の誤差であっても許容できません。監査では合計が1セント単位まで一致することが求められます。
そのため、金額を浮動小数点型で保存してはいけません。
解決策:BigDecimal
Javaには、小数を正確に保存するクラスBigDecimalが用意されています。非スケールド値とスケールを別々に管理するため、0.1は本当に0.1を意味します。
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
System.out.println(a.add(b));
}
}Stringコンストラクターを必ず使用する
BigDecimalはdoubleではなくStringから作成してください。doubleを渡すと、2進数の誤差がBigDecimalに持ち込まれます。
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
BigDecimal fromDouble = new BigDecimal(0.1);
BigDecimal fromString = new BigDecimal("0.1");
System.out.println(fromDouble);
System.out.println(fromString);
}
}またはvalueOfを使用する
BigDecimal.valueOfは安全な簡略方法です。doubleを標準的な文字列表現に変換してから扱うため、元の2進数の誤差を避けられます。
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
BigDecimal price = BigDecimal.valueOf(19.99);
System.out.println(price);
}
}金額をセントで保存する
単純なケースでは、longを使って金額を整数のセント数として保存する方法もあります。すると19.99ドルは1999セントとなり、すべての計算を正確な整数演算で行えます。
public class Main {
public static void main(String[] args) {
long cents = 1999;
long total = cents * 3;
System.out.println(total + " cents");
}
}要点
小さな誤差が許容される科学計算やグラフィックスではfloatとdoubleを使用してください。金額や正確さが必要な値には、BigDecimalまたは整数のセント数を使用してください。
理解度チェック
浮動小数点の精度について、理解度を確認しましょう。
まとめ
doubleが金額の扱いに適さない理由について学びました。
- 2進浮動小数点では多くの小数を正確に保存できない
0.1 + 0.2が0.3と等しくならないような誤差が蓄積する- 正確な小数演算には
BigDecimalを使用する - Stringから作成するか
valueOfを使用し、生のdoubleからは決して作成しない - 整数のセント数で保存する方法もある
よくある質問
「金額にdoubleを使わない理由」レッスンは無料ですか?
はい。「金額にdoubleを使わない理由」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「金額にdoubleを使わない理由」で何を学びますか?
浮動小数点の精度問題を学びます ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「金額にdoubleを使わない理由」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 金額にdoubleを使わない理由
- BigDecimalの操作
- 丸めとスケール
- 巨大な数値のためのBigInteger