4

Java (JDK 1.4) での 10 進数の管理に問題があります。

最初2番目に2つの二重数値があります(フォーマットされたStringの出力として)。拳と秒の合計を計算すると、10 進数の桁数が多い数値が得られます。

   final double first=198.4;//value extract by unmodifiable format method

   final double second=44701.2;//value extract by unmodifiable format method

   final double firstDifference= first+second; //I receive 44899.598 instead of 44899.6

   final double calculatedDifference=44900.1; // comparison value for the flow

    final double error=firstDifference-calculatedDifference;// I receive -0.50390605 instead 0.5

    if(Math.abs(error)<=0.5d)){
         //I must enter in this branch but the error not allows the correct flow!!!
    }
    /***
    * the flow of program is uncorrect and there's a very visible bug in business view
    */

同様の状況では安全ではないため、しきい値(0.5d )を大きくしないことを好みます(コーディングを開始したとき、仕様では比較値として0.1dについて話していました)。それが唯一の解決策である場合、この問題に対して0.9dの値が最も安全な値ですか?

どうすればこの状況を解決できますか? この問題は double 変数の使用によって派生すると考えましたが、float でも同じ問題があります。

いくつかのアイデア(可能であれば、テスト済みのコード行があります;))?

4

5 に答える 5

3

このエラーは、Java のバージョンによって多少異なります (少し古いバージョンを使用しているようです)。ただし、Java のバージョンに関係なく、Java で小数の精度が特に気になる場合に最良の結果を得るにはBigDecimal、値にクラスを使用する必要があります。

これは、金融アプリケーションが通貨を処理するために使用するものであり、多くの産業用 Java アプリケーションが精度が不可欠な場合に使用するものでもあります。

編集:このソリューションにはわずかなパフォーマンスの低下が伴うという有効なコメントがたくさんあります(最初に行っている操作の数にも依存します)。実際、これが問題に遭遇した唯一の場所であり、その後の精度を気にしない場合は、回避策を探してください. ただし、これが複数の場所で頻繁に発生する場合、または将来アプリケーションを拡張する可能性がある場合は、より安全なBigDecimal.

于 2011-03-24T18:19:03.867 に答える
3

丸め誤差が発生する可能性がありますが、ここには表示されません。

final double first=198.4;//value extract by unmodifiable format method
final double second=44701.2;//value extract by unmodifiable format method
final double firstDifference= first+second; //I receive 44899.6
final double calculatedDifference=44900.1; // comparison value for the flow
final double error=firstDifference-calculatedDifference;// I receive -0.5 

if(Math.abs(error)<=0.5d){
    // this branch is entered.
    System.out.println(error);
}

版画

-0.5

これをより一般的に処理するには、2 つの方法があります。次のような丸め誤差を定義できます。

 private static final double ERROR = 1e-9;

 if(Math.abs(error)<=0.5d + ERROR){

または丸めを使用する

final double firstDifference= round(first+second, 1); // call a function to round to one decimal place.

OR 固定精度の整数を使用

final int first=1984;// 198.4 * 10
final int second=447012; // 44701.2 * 10
final int firstDifference= first+second;  //I receive 448996
final int calculatedDifference=449001; // comparison value for the flow
final int error=firstDifference-calculatedDifference;// I receive -5 

if(Math.abs(error)<=5){
    // this branch is entered.
    System.out.println(error);
}

または BigDecimal を使用できます。多くの場合、これは多くの開発者に好まれるソリューションですが、私見では最後のオプションです。;)

于 2011-03-24T18:16:51.433 に答える
0

私はテストしましたが、私のマシンではすべてが正しいです (Java 1.6 でテスト済み)。私があなただったら、上記の操作を持つメソッドに対して strictfp 修飾子をテストします。

public static strictfp void main(String[] args)

問題は、使用しているJavaのバージョン、OS、CPUに関連している可能性があります

于 2011-03-24T18:20:32.773 に答える
0

私もピーターに同意します。ただし、それが引き続き発生し、ユースケースで小数点以下の桁数がわかっている場合は、「int」を使用することが解決策になる可能性があります。これは、浮動小数点演算よりも高速です。もちろん、ビューの場合は浮動小数点に変換する必要があります。

于 2011-03-24T18:55:47.610 に答える
0

Double アイテムは 2 のべき乗で数値を格納します。2 のべき乗で多くの数値を正確に表現することはできないため、丸めの問題が発生します。フロートを使用する場合も同じ問題です。

これらを減らしたい場合は、数値に Decimal 型を使用すると、より正確になるはずです。

double と float の場合、< コンパレータを使用して、2 つの数値が等しいと見なされるほど近いかどうかを確認する必要があります。

詳細については、これを参照してください-> float と double の比較で最も効果的な方法は何ですか?

于 2011-03-24T18:17:42.037 に答える