Javaにおけるデジタル基本演算と精度の問題



一.精度
 
例:double result=1.0-0.9;
この結果は言うまでもないでしょうが、わかりました、0.09999999999999998
floatとdoubleタイプは主に科学計算とエンジニアリング計算のために設計されている.彼らは、広範な数値範囲でより正確な高速近似計算を提供するために丹念に設計されたバイナリ浮動小数点演算を実行する.しかし,それらは完全に正確な結果を提供していないので,正確な計算の場合に用いるべきではない.floatタイプとdoubleタイプは特に通貨演算に適していません.1つのfloatまたはdoubleに0.1または10を正確に表す他の負の次数の値を正確に表すことは不可能です(実際には簡単ですが、10進数システムでは1/3を正確に表すことができますか?同じように2進数系でも1/10を正確に表すことはできません).
浮動小数点演算は正確であることは少なく,精度が表す範囲を超えると誤差が生じる.誤差が生じるのは数の大きさではなく、数の精度のためであることが多い.したがって、結果は所望の結果に近いが等しくない.特にfloatとdoubleを使用して正確な演算を行う場合は特に注意してください.
 
 
double result = 1.0 - 0.9;//   
 
 
 
二.精度損失を解決するにはいくつかの比較的よく使われる方法がある.
 
1.計算結果をNumberFormatクラスでフォーマットし、自分の望む結果に従ってフォーマットする欠点は、手動でフォーマットすることであり、切り込み方法によって結果が正確ではないことです.
 
//    
double result = 1.0 - 0.9;
NumberFormat nf = NumberFormat.getInstance();//           
String resultStr = nf.format(result);
 
 
 
2.自分で10進数の小数点を記録しても構わないし、数値が大きくない場合は、long、intなどの基本タイプを使うことができます.具体的にintを使うかlongを使うかは、関連する数値範囲の大きさによって異なります.欠点は、10進数の小数点を自分で処理することです.最も明らかな方法は、元を使わずに通貨を処理することです(増減のみ).
 
//    
int resultInt = 10 - 9;
double result = (double) resultInt / 100;//           
 
 
 
3.doubleの代わりにBigDecimalを使用すると、精度を完全に制御でき、結果が非常に正確になり、加減乗除して書くのも便利ですが、2つの欠点があります.1、基本タイプではなく、基本タイプに比べて操作が不便です.2.速度は基本タイプほど速くなく、速度で精度を変える.2つ目の欠点に比べて大丈夫ですが、1つ目の欠点はコードを書くのが不快です.
 
//    
String result = new BigDecimal("1").subtract(new BigDecimal("0.9")) .toString();
 
 
個人的にはこれが好きで、BigDecimalはよく使われるフォーマット方法をサポートしています.
BigDecimal num = new BigDecimal("384400000");
String str=new DecimalFormat("地球と月の距離:#,##,##,###,####,####,####").format(num);
結果:地球と月の距離:384400000メートル
 
 
//     double float      ,     。//    
//              。//    
 
 
 
三.浮動小数点タイプの比較
精度の問題でdouble/floatは比較的等しくても直接使用できません==ただし、比較サイズは<、>番号で使用できます
 
 
double d1 = 0.1, d2 = 0.1;
if (d1 == d2) {}//    
if (Double.compare(d1, d2) == 0) {}//    
if (Double.doubleToLongBits(d1) == Double.doubleToLongBits(d2)) {}//    
if (Double.valueOf(d1).equals(d2)) {}//    ,1.5  
 
 
 
四.第三者ツール類の合理的な使用
apacheのcommons-langツールパッケージのmathパッケージは、一般的な計算方法、デジタル処理方法を提供しています.プロジェクトに関連する計算が多い場合は、commons-mathパッケージを使用することを考慮することができます.このパッケージは専門化しすぎて、私たちが使っているところは多くないと思います.
apacheのcommons-langのmathパッケージは、主に4つの機能があります
1.スコアを扱うFractionクラスで、スコアは数字を表し、より正確である.
 
Fraction fraction = Fraction.getFraction(10, 3);//     
System.out.println(fraction);// 10/3
System.out.println(fraction.floatValue());// 3.3333333
System.out.println(fraction.doubleValue());// 3.3333333333333335
System.out.println(fraction.toProperString());//       
System.out.println(fraction.reduce());//   , 2/4   1/2
 
 
2.数値を扱うNumberUtilsクラス;これは簡単です.apiを見てください.デジタル変換、比較、1つのデジタル配列の最大値、最小値など、一般的なデジタル操作方法がカプセル化されています.
3.数値範囲のRange、NumberRange、IntRange、LongRange、FloatRange、DoubleRangeクラスを扱う.
 
//  int  ,    
IntRange intRange = new IntRange(100, 200);//       
intRange.containsDouble(111.1);//         
int[] range = intRange.toArray();//       int
intRange.getMaximumDouble();//      ,   double
intRange.getMinimumDouble();//      ,   double
 
 
4.乱数のJVMRandomとRandomUtilsクラスを処理します.これも簡単ですが、apiを見ればいいので、乱数を取得するのに便利です.
 
commons-mathツールパッケージはapacheの前の軽量レベルの自己容器の数学と統計計算方法パッケージであり、多くの一般的な数値アルゴリズムが含まれており、これは専門的な数学処理を行う際に非常に便利である.
例えば:計算方法、分散と1組の数の確率統計問題;
曲線にフィットするデータ点に線形回帰問題を適用する.
補間問題(線形、スプラインなどの補間を含む可能性があります).
パラメータフィッティングを行うための最小二乗方法;
方程式のグループ値の問題を解く(例えば、方程式のグループのルートを求める);
システムの線形方程式グループを解決する.
常微分方程式を解く.
最小値の問題を求める方法;
Commons Mathパッケージを使用して、指定された要求の乱数を生成します.
ランダムサンプリング、データセットを生成します.
統計テストを行う.
グループ二項式係数、特殊関数(gamma、beta functionsなど)などの複雑な数学関数.
個人的にはこのパッケージは専門的すぎると思いますが、使ったら、後で調べても遅くないので、このパッケージが問題を解決できることを知っていればいいです.
もちろん、このバッグは専門的ですが、専門的な数学の問題しか解決できないわけではありません.簡単な計算を処理するのも便利です.
 
まとめ:一般的な計算はBigDecimalクラスを使用することが望ましい.このクラスは結果を非常に正確に計算することができ、精度を完全に制御することができ、他の操作を必要とせず、基本的なタイプとの変換も非常に便利である.