Javaに倍精度数を返すメソッドがあり、メソッドを呼び出すたびに(たとえば5回)返される倍精度数をすべて比較したいので、返される数は毎回ほぼ同じです。
これどうやってするの?
まず、「ほぼ同じ」の意味を決定する必要があります。たとえば、_Java.lang.Math
_には lp() と呼ばれるメソッドがあり、doubleを指定すると、そのdoubleと次のdoubleの間の距離を返します。つまり、その数と他の数との間の可能な最小の差。 2つのdoubleの違いとそのメソッドを呼び出した結果を単純に比較できます。
一方、2つの数値が互いに1%以内に収まるようにしたい場合があります。その場合、同じ計算を行いますが、ulp()
ではなく、_0.01
_を掛けた最初の数値を最大許容距離として使用します。
public static boolean almostEqual(double a, double b, double eps){
return Math.abs(a-b)<eps;
}
ここで、epsは平等の尺度です。
近似等式は絶対差で定義されます。絶対差が特定の、おそらく小さい数を超えない場合、比較している値は「十分に近い」と言えます。
double diff = Math.abs(actual - expected);
if (diff < 1E-7) {
// Numbers are close enough
}
「十分に近い」と「等しい」を混同しないように十分に注意する必要があります。2つは根本的に異なるためです。十分」は推移的ではありません。
それはあなたが同様にどういう意味かによって異なります。絶対誤差の範囲内で2つの数値を比較したい場合。 1e-6あなたはイプシロンを使用できます。スケールに関係なく2つのdouble
を比較する場合。例えば1.1e-20と1.3e-20は似ていませんが、1.1e20と1.1e20 + 1e5は生の値を比較できます。
public static void main(String... args) throws IOException {
test(1.1e-20, 1.3e-20);
test(1.1e20, 1.1e20 + 1e5);
}
private static void test(double a, double b) {
System.out.println(a + " and " + b + ", similar= " + similarUnscaled(a, b, 10));
}
public static boolean similarUnscaled(double a, double b, long representationDifference) {
long a2 = Double.doubleToRawLongBits(a);
long b2 = Double.doubleToRawLongBits(b);
// avoid overflow in a2 - b2
return ((a2 >= 0) == (b2 >= 0)) &&
Math.abs(a2 - b2) <= representationDifference;
}
プリント
1.1E-20 and 1.3E-20, similar= false
1.1E20 and 1.100000000000001E20, similar= true
GuavaとDoubleMath#fuzzyEquals
メソッドを使用できます(バージョン13.0以降):
public static boolean fuzzyEquals(double a, double b, double tolerance)
Aとbが互いの許容範囲内にある場合、trueを返します。技術的には、これはMath.abs(a-b)<=許容値||と同等です。 Double.valueOf(a).equals(Double.valueOf(b))。
注目すべき特殊なケースは次のとおりです。
ドキュメントへのリンク: https://google.github.io/guava/releases/17.0/api/docs/com/google/common/math/DoubleMath.html
2つのダブルスが「ほぼ等しい」とはどういう意味ですか?これは、ダブルが互いにある程度の許容範囲内にあることを意味します。その許容誤差のサイズ、およびその許容誤差が絶対値として表されるか、2つのdoubleのパーセンテージとして表されるかは、アプリケーションによって異なります。
たとえば、フォトビューアに表示される2つの写真は、画面上で同じピクセル数を占める場合、幅がほぼ同じインチになるため、画面のピクセルサイズに基づいて計算された絶対数になります。一方、2つの金融会社の利益は、0.1%以内であれば「ほぼ等しい」と考えられます。これらは単なる架空の例ですが、重要なのはアプリケーションによって異なるということです。
今いくつかの実装のために。あなたのアプリケーションが絶対的な許容を要求するとしましょう。その後、使用できます
private static final double TOLERANCE = 0.00001;
public static boolean approxEqual(final double d1, final double d2) {
return Math.abs(d1 - d2) < TOLERANCE;
}
2つのdoubleを比較し、使用するには
approxEqual(d1, d2) && approxEqual(d1, d3) && approxEqual(d1, d4) && approxEqual(d1, d5)
5つのダブルを比較します。
Apache commons-mathライブラリは、Nice Precision
クラスを提供します( API Docs を参照)。さまざまな方法でダブルス:
Precision.equals(a, b, 0.1); // Tell if |a-b| <= 0.1
Precision.equals(a, b, 10); // Tell if a and b are less than 10 Ulps apart
Precision.equalsWithRelativeTolerance(a, b, 0.05); // Tell if a and b are less than 5% apart