2013-04-14 5 views
5

के लिए एक HashSet बनाना एक परिभाषित सहिष्णुता (epsilon) का उपयोग कर (सीएफ Assert.assertEquals(double, double, double)
के बाद से Double.equals() का उपयोग कर केवल सटीक समानता के लिए काम करता है और Double एक अंतिम वर्ग है मैं इसका उपयोग नहीं कर सकता। मेरा प्रारंभिक विचार HashSet (उदाहरण के लिए DoubleHashSet) को setEpsilon(double) विधि के साथ विस्तारित करना है और एक नई कक्षा ComparableDouble बनाएं जहां equals()DoubleHashSet से इस मान का उपयोग करता है। हालांकि मैं यह जांचना चाहता हूं कि मौजूदा समाधान हैं या नहीं पहले से ही और मौजूदा एफ/ओएसएस पुस्तकालय।मैं वास्तविक संख्या के लिए एक <code>HashSet</code> (वर्तमान <code>Double</code> रों पर) बनाना चाहते डबल्स

(वें भविष्य में मैं इसे वास्तविक संख्याओं के tuples में विस्तारित करना चाहता हूं - उदा। आयताकार और क्यूब्स - इसलिए एक सामान्य दृष्टिकोण बेहतर है

नोट: @ एनपीई ने सुझाव दिया है कि यह असंभव है। दुर्भाग्यवश मुझे संदेह है कि यह औपचारिक रूप से सही है :-) तो मैं सोच रहा हूं कि अनुमानित तरीके हैं ... अन्य लोगों को यह समस्या होनी चाहिए और इसे लगभग हल किया जाना चाहिए। (मैं पहले से ही नियमित रूप से एक उपकरण Real.isEqual(a, b, epsilon) का उपयोग करता हूं और यह बहुत उपयोगी है।) मैं पारगमन की कुछ कम त्रुटियों को स्वीकार करने के लिए तैयार हूं।

नोट: मैं ट्रीसेट का उपयोग करूंगा क्योंकि यह "लगभग बराबर()" की समस्या को हल करता है। बाद में मैं जटिल नर्स, आयताकार (और अधिक जटिल वस्तुओं) की तुलना करूँगा और यह वास्तव में उपयोगी है कि वह एक सीमा निर्धारित करने में सक्षम हो जिसमें 2 चीजें बराबर हों। जटिल नब्स का कोई साधारण प्राकृतिक क्रम नहीं है (शायद एक कैंटर दृष्टिकोण काम करेगा), लेकिन हम बता सकते हैं कि वे लगभग बराबर हैं या नहीं।

+0

आप है यहां सही रास्ते पर दिखने लगते हैं। डबल विस्तार और आपके बराबर कार्यान्वयन प्रदान करना सही दृष्टिकोण प्रतीत होता है। – anubhava

+1

@anubhava OK - मैं टिप्पणी के लिए कुछ डमी कोड जोड़ूंगा –

+0

@anubhava ने कोड को हटा दिया है क्योंकि अन्य उत्तरों ने इसे –

उत्तर

4

इस दृष्टिकोण में कुछ मौलिक त्रुटियां हैं।

HashSet समानता के लिए दो तत्वों की जांच के लिए equals() का उपयोग करता है। The contract on equals() has the following among its requirements:

यह सकर्मक है: किसी भी गैर-शून्य संदर्भ मूल्यों के लिए x, y, और z, अगर x.equals(y) रिटर्न true और y.equals(z) रिटर्न true, तो x.equals(z)true लौटना चाहिए।

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

यह स्पष्ट है कि अपने प्रस्तावित तुलना योजना संक्रामिता आवश्यकता टूट जाएगा (x के बराबर होती है y और y के बराबर होती है z, अभी तक x बराबर z नहीं करता है):

अब निम्न उदाहरण पर विचार करें। इन परिस्थितियों में, HashSet सही ढंग से कार्य नहीं कर सकता है। equals(Object) विधि के अनुसार,

तो दो वस्तुओं के बराबर हैं तो दो वस्तुओं में से प्रत्येक पर बुला hashCode विधि एक ही उत्पादन होगा:

इसके अलावा, hashCode() अतिरिक्त चुनौतियों के कारण निम्नलिखित requirement का उत्पादन करेगा पूर्णांक परिणाम।

hashCode() आवश्यकता एक TreeSetHashSet के बजाय का उपयोग करके किनाराकशी कर ली जा सकती है।

+0

का अधिग्रहण किया है, मुझे एक डूबने वाली भावना है कि आप सही हैं। लेकिन मैं इसमें थोड़ी सी विफलता के लिए तैयार हूं। उदाहरण के लिए मैं हैशकोड() के रूप में 10 * (- लॉग (ईपीएसलॉन)) के निकटतम पूर्णांक बना सकता हूं। यदि यह कभी-कभी विफल रहता है तो यह दुनिया का अंत नहीं होगा। –

+0

'हैशकोड()' समस्या को 'ट्रीसेट' के बजाय उपयोग करके रोका जा सकता है, लेकिन पारगमन आवश्यकता एक ही रहती है। –

+0

@ फिलिप वादा करता है। क्या आप मुझे एक उदाहरण दे सकते हैं? –

1

मुझे क्या उन्हें प्रयोग करने से पहले युगल दौर है (यह मानते हुए उचित है)

उदा

public static double roundByFactor(double d, long factor) { 
    return (double) Math.round(d * factor)/factor; 
} 

TDoubleHashSet set = new TDoubleHashSet(); // more efficient than HashSet<Double> 
set.add(roundByFactor(1.001, 100)); 
set.add(roundByFactor(1.005, 100)); 
set.add(roundByFactor(1.01, 100)); 
// set has two elements. 

आप इस व्यवहार को अपने डबलशैशसेट में लपेट सकते हैं। यदि आप मूल मान आरक्षित करना चाहते हैं तो आप हैश मैप या TDoubleDoubleHashMap का उपयोग कर सकते हैं जहां कुंजी गोलाकार मान है और मान मूल है।

+0

बहुत धन्यवाद। क्या मुझे लगता है कि यह 'gnu.trove.set.hash.TDoubleHashSet' है? यदि ऐसा है तो यह लगता है कि (पहली नज़र में) जो मैं खोज रहा हूं, जब तक कि उसके पास जीपीएल लाइसेंस न हो। [http://trove4j.sourceforge.net/javadocs/gnu/trove/set/hash/TDoubleHashSet.html] –

+1

यह एलजीपीएल है जो मेरे समुदाय और अधिकांश वितरण रणनीतियों के लिए ठीक है –

0

मैं @ एनपीई का दृष्टिकोण को लागू किया है (मैं उसकी/उसके जवाब इतना s/वह :-) अंक हो जाता है स्वीकार किए जाते हैं और यहाँ कोड

//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()); 
} 
+0

नोट: मैंने इसे संख्याओं के tuples के लिए लागू किया है । चूंकि कोई प्राकृतिक आदेश नहीं है, यह "अजीब तरीके से व्यवहार करता है" - यह इच्छित सेट के कई सबसेट बना सकता है। –

संबंधित मुद्दे