5

定義された許容範囲 ( ) を使用してHashSet(現在 s) の実数の を作成したい(cf を使用すると、正確な等価性に対してのみ機能し、最終的なクラスであるため、使用できません。私の最初のアイデアは、拡張することです(たとえば、)、メソッドを使用して、 からこの値を使用する新しいクラスを作成します.ただし、既存のソリューションと既存の F/OSS ライブラリがあるかどうかを確認したい.DoubleepsilonAssert.assertEquals(double, double, double)
Double.equals()DoubleHashSetDoubleHashSetsetEpsilon(double)ComparableDoubleequals()DoubleHashSet

(将来的には、これを実数のタプル (長方形や立方体など) に拡張したいと考えているため、一般的なアプローチが望ましい

注: @NPE は、それは不可能だと示唆しています。残念ながら、これは正式には正しいと思います:-)おおよその方法があるかどうか疑問に思っています...他の人はこの問題を抱えていて、おおよそ解決したに違いありません。(私はすでにツールReal.isEqual(a, b, epsilon)を定期的に使用しており、非常に便利です。) 私は、推移性のまれなエラーを受け入れる準備ができています。

注: 「nearly equals()」の問題を解決するため、TreeSet を使用します。後で、complexNumbers、長方形 (およびより複雑なオブジェクト) を比較しますが、2 つのものが等しい範囲内で制限を設定できると非常に便利です。complexNumbers の単純で自然な順序付けはありません (おそらく Cantor アプローチが機能するでしょう) が、それらがほぼ等しいかどうかはわかります。

4

3 に答える 3

5

このアプローチにはいくつかの根本的な欠陥があります。

HashSetequals()2 つの要素が等しいかどうかをチェックするために使用します。の契約にequals()は、その要件の中に次のものがあります

これは推移的です: null 以外の参照値xy、およびに対して、が返され、が返さzれる場合は、が返されます。x.equals(y)truey.equals(z)truex.equals(z)true

次の例を考えてみましょう。

x = 0.0
y = 0.9 * epsilon
z = 1.8 * epsilon

提案された比較スキームが推移性の要件を破ることは明らかです ( xequalsyyequals z、 but xdoes not equal z)。このような状況では、HashSet正しく機能できません。

さらに、次の要件hashCode()により、追加の課題が発生します。

メソッドに従って 2 つのオブジェクトが等しい場合、2 つのオブジェクトのそれぞれでメソッドequals(Object)を呼び出すとhashCode、同じ整数の結果が生成される必要があります。

の代わりにa を使用することで、このhashCode()要件を回避できます。TreeSetHashSet

于 2013-04-14T09:40:58.527 に答える
0

私は@NPEのアプローチを実装しました(私は彼/彼女の答えを受け入れたので、ポイントを取得しました:-)、ここにコードを与えます

//Create a comparator:
public class RealComparator implements Comparator<Double> {

    private double epsilon = 0.0d;

    public RealComparator(double eps) {
        this.setEpsilon(eps);
    }

    /**
     * if Math.abs(d0-d1) <= epsilon  
     * return -1 if either arg is null
     */
    public int compare(Double d0, Double d1) {
        if (d0 == null || d1 == null) {
            return -1;
        }
        double delta = Math.abs(d0 - d1);
        if (delta <= epsilon) {
            return 0;
        }
        return (d0 < d1) ? -1 : 1;
    }

    /** set the tolerance
     * negative values are converted to positive
     * @param epsilon
     */
    public void setEpsilon(double epsilon) {
        this.epsilon = Math.abs(epsilon);
    }

そしてそれをテストする

public final static Double ONE = 1.0;
public final static Double THREE = 3.0;

@Test
public void testTreeSet(){
    RealComparator comparator = new RealComparator(0.0);
    Set<Double> set = new TreeSet<Double>(comparator);
    set.add(ONE);
    set.add(ONE);
    set.add(THREE);
    Assert.assertEquals(2, set.size());
}
@Test
public void testTreeSet1(){
    RealComparator comparator = new RealComparator(0.0);
    Set<Double> set = new TreeSet<Double>(comparator);
    set.add(ONE);
    set.add(ONE-0.001);
    set.add(THREE);
    Assert.assertEquals(3, set.size());
}
@Test
public void testTreeSet2(){
    RealComparator comparator = new RealComparator(0.01);
    Set<Double> set = new TreeSet<Double>(comparator);
    set.add(ONE);
    set.add(ONE - 0.001);
    set.add(THREE);
    Assert.assertEquals(2, set.size());
}
@Test
public void testTreeSet3(){
    RealComparator comparator = new RealComparator(0.01);
    Set<Double> set = new TreeSet<Double>(comparator);
    set.add(ONE - 0.001);
    set.add(ONE);
    set.add(THREE);
    Assert.assertEquals(2, set.size());
}
于 2013-04-14T12:39:24.360 に答える