(1) Javaでの誤差の対処法
(1-1) 対処が必要なケース
(1-2) 対処の方法
(1-2-1) BigDecimalクラスでの対処
(1-2-2) int型を優先的に使い対処
(1-2-3) double型の使い方を工夫して対処
(1) Javaでの誤差の対処法
誤差は小さいものの、累積していくと非常に大きな差分になる上に、if文等の比較では一致しなくなるため、問題となります。
(1-1) 対処が必要なケース
しかし、対処が必ずしも必要という訳ではなく、当然ながら対処した分は性能が落ちるため、システムの目的に応じて処置の有無も変わってきます。例えば、銀行のシステムなど誤差の許されない業務においては厳格な対処が必要となりますが、一方で科学分野などでは有効数字の概念など、そもそも非常に小さな値などは考慮しない考え方があるため、double型の誤差のオーダーでは処置不要と考えられます。
(表)
優先項目 | 対処方法 | 該当分野(例) |
計算速度を優先 | – (対処不要) |
・科学分野 ・技術分野 (※有効数字など極小値は無視できるケースなどがある) |
計算精度を優先 | ①BigDecimalクラスを使う ②極力int型で計算を行う ③工夫してdouble型を使う |
・金融系システム |
(1-2) 対処の方法
上記で記載した①~③の対処方法について記述します。
(1-2-1) BigDecimalクラスでの対処
別記事にて詳細に記述(⇒★2020年9月中作成予定)
(1-2-2) int型を優先的に使い対処
もし計算プロセスの中で途中まででもintで進められるのであれば、intを使うようにします。もし除算など最後にdouble型が必要となる場面でのみdoubleを使う事で誤差を最小限に留める事ができます。
(サンプルPG)
public class IT0126_Double_Error { public static void main (String args[]) { d_err_sol1_p2(6.29,2.48,1.23); } public static void d_err_sol1_p2(double price1, double price2, double price3) { //引数(ドル)に100を掛けてセントに換算 //その際にint型にキャストして、最後の除算まではint型で計算を進める int pc1 = (int)(price1*100); int pc2 = (int)(price2*100); int pc3 = (int)(price3*100); System.out.println("pc1= "+pc1+", pc2= "+pc2+", pc3= "+pc3); //極力int型で計算を進める int sum = pc1+pc2+pc3; //最後に割合を算出する時だけdouble型にキャストする //→除算前にキャストしないと、分母分子ともに小数点以下が切り捨てされてしまうため //→分子がdouble型にキャストされれば、分母は暗黙的にdouble型にキャストされる double rate1 = (double)pc1/sum; double rate2 = (double)pc2/sum; double rate3 = (double)pc3/sum; System.out.println("rate1= "+rate1+", rate2= "+rate2+", rate3= "+rate3); } }
(図222)
(1-2-3) double型の使い方を工夫して対処
double型には誤差がある前提で、比較のロジックなどは通常は完全一致とする所を、誤差の分だけ「範囲」を持たせて比較するように変更します。
(サンプルPG)
public class IT0126_Double_Error2 { public static void main (String args[]) { //↓結果は10.0には戻らず、9.999999999999998になってしまう計算 //そのため、10.0との誤差は(2E-15)となり次のif分岐で②の条件に合致する想定 double db1 = 10.0 / 154.0 * 154.0; //①10.0と比較しても一致しない if(db1==10.0) { System.out.println("完全一致で同じ値です"); //②10.0±(10E-10)の範囲と一致するか?を確認 }else if(doubleCheck(10.0,db1)) { System.out.println("誤差±10E-10の範囲では一致します"); //③それ以外のパターン(誤差が10E-10以上) }else { System.out.println("誤差が±10E-10以上あります"); } } //doubleCheck()メソッド //<処理概要> //引数に与えた2つのdouble型の変数の差の絶対値(abs)が10E-10の範囲内に収まっているか?の確認 public static boolean doubleCheck(double d1, double d2) { System.out.println("d1= "+d1); System.out.println("d2= "+d2); return Math.abs(d1-d2) < 0.0000000001; } }
(図223)
>目次にもどる