Rainbow Engine

IT技術を分かりやすく簡潔にまとめることによる学習の効率化、また日常の気付きを記録に残すことを目指します。

Java

Javaでdouble型での誤差を対処する方法について+サンプルプログラムも紹介

投稿日:2020年9月18日 更新日:

(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)

目次にもどる

Adsense審査用広告コード


Adsense審査用広告コード


-Java

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

関連記事

Javaのthisとは?コンストラクタで引数を与えている場合・メソッド引数に使われる場合もご紹介

<目次> (1) Javaのthisとは?コンストラクタに出現する場合やメソッド引数に使われる場合もご紹介  (1-1) thisとは?  (1-2) 用途1:自分自身を指定【重要】  (1-3) 用 …

Javaのenumでフィールドを複数定義したり、値を取得する方法

<目次> (1) Javaのenumでフィールドを複数定義したり、値を取得する方法  (1-1) enumでフィールドを定義・取得する  (1-2) enumでフィールドを複数定義・取得する (1) …

Javaでファイルへの書き込みする方法の基礎(追記・上書き、改行の方法等)

<目次> (1) Javaでファイルへの書き込みする方法の基礎(追記・上書き、改行の方法等)  (1-1) STEP1:FileWriterクラスのインスタンス化  (1-2) STEP2:ファイルへ …

オープンアドレス法をJavaで実装したプログラムのサンプルをご紹介

<目次> (1) オープンアドレス法をJavaで実装したプログラムのサンプルをご紹介  (1-1) オープンアドレス法とは  (1-2) Javaのサンプルプログラムの全体像  (1-3) Javaの …

JNDIとは?JDBCとの違いやメリット・デメリットについてもご紹介

<目次> (1) JNDIとは?JDBCとの違いやメリット・デメリットについてもご紹介  (1-1) JDBCとは?  (1-2) JNDIとは?   (1-2-1) 概要   (1-2-2) JND …

  • English (United States)
  • 日本語
Top