2013-02-19 26 views
22

यह सब एक चाल प्रश्न के साथ शुरू हुआ कि किसी ने मुझे देखा .. (पुस्तक में इसका उल्लेख है - सी # संक्षेप में) यहां इसकी जानकारी है।डबल का == ऑपरेटर कब आवेदित होता है?

Double a = Double.NaN; 
Console.WriteLine(a == a); // => false 
Console.WriteLine(a.Equals(a)); // => true 

उपरोक्त सही नहीं लगता है। हमेशा अपने आप को == होना चाहिए (संदर्भ समानता) & दोनों को सुसंगत होना चाहिए।

लगता है जैसे == ऑपरेटर डबल ओवरलोड करता है। परावर्तक से इसकी पुष्टि इस प्रकार है:

[__DynamicallyInvokable] 
public static bool operator ==(double left, double right) 
{ 
    return (left == right); 
} 

अजीब है कि पुनरावर्ती लग रहा है और NaN विशिष्ट व्यवहार का कोई जिक्र नहीं। तो यह झूठी क्यों लौटता है?

तो मैं

var x = "abc"; 
var y = "xyz"; 
Console.WriteLine(x == y); // => false 

भेद करने के लिए कुछ और कोड जोड़ने अब मैं देख रहा हूँ

L_0001: ldc.r8 NaN 
    L_000a: stloc.0 
    L_000b: ldloc.0 
    L_000c: ldloc.0 
    L_000d: ceq 
    L_000f: call void [mscorlib]System.Console::WriteLine(bool) 
    L_0014: nop 
    L_0015: ldloca.s a 
    L_0017: ldloc.0 
    L_0018: call instance bool [mscorlib]System.Double::Equals(float64) 
    L_001d: call void [mscorlib]System.Console::WriteLine(bool) 
    L_0022: nop 
    L_0023: ldstr "abc" 
    L_0028: stloc.1 
    L_0029: ldstr "xyz" 
    L_002e: stloc.2 
    L_002f: ldloc.1 
    L_0030: ldloc.2 
    L_0031: call bool [mscorlib]System.String::op_Equality(string, string) 
    L_0036: call void [mscorlib]System.Console::WriteLine(bool) 
    डबल्स के लिए
  • , == ऑपरेटर कॉल एक ceq आईएल opcode
  • जहां के रूप में करने के लिए अनुवाद तारों के लिए, यह सिस्टम.स्ट्रिंग :: op_Equality (स्ट्रिंग, स्ट्रिंग) में अनुवाद करता है।

निश्चित रूप से documentation for ceq निर्दिष्ट करता है कि यह फ़्लोटिंग पॉइंट नंबर और NaN के लिए विशेषीकृत है। यह अवलोकन बताता है।

सवाल:

  • क्यों op_Equality डबल पर परिभाषित किया गया है? (और कार्यान्वयन NaN विशिष्ट व्यवहार में कारक नहीं है)
  • इसे कब लागू किया जाता है?
+2

परावर्तक अक्सर ऐसी स्थितियों में विफल रहता है। मुझे लगता है कि 'ऑपरेटर ==' खुद को कॉल नहीं करता है, बल्कि आंतरिक रूप से 'ceq' का उपयोग करता है। – CodesInChaos

+0

मुझे लगता है कि यह वही समस्या है जैसे http://stackoverflow.com/q/14458890/1236044 – jbl

+0

@ jbl- वह सवाल पूछ रहा है कि क्यों 2 बराबर अलग-अलग परिणाम लौटाते हैं - जो मुझे लगता है। मेरा सवाल प्रतीत होता है कि अनावश्यक स्थिर op_equality कार्यान्वयन जो कभी नहीं कहा जाता है। – Gishu

उत्तर

11

परावर्तक के गलत व्याख्या

decompilation कि आप परावर्तक से देख रहे हैं वास्तव में परावर्तक में एक बग है। परावर्तक को एक समारोह को कम करने में सक्षम होना चाहिए जहां दो युगल की तुलना की जा रही है; उन कार्यों में, आपको ceq कोड में सीधे लगाया जाएगा। नतीजतन, प्रतिबिंबक एक ceq निर्देश को दो युगल के बीच == के रूप में व्याख्या करता है ताकि दो युगल की तुलना में एक समारोह को विघटित करने में मदद मिल सके।

डिफ़ॉल्ट रूप से, मान प्रकार एक == कार्यान्वयन के साथ नहीं आते हैं। (Don't user-defined structs inherit an overloaded == operator?) हालांकि, सभी अंतर्निहित स्केलर प्रकारों में स्पष्ट रूप से अधिभारित ऑपरेटर होता है जो संकलक उपयुक्त सीआईएल में का अनुवाद करता है। अधिभार में एक साधारण ceq आधारित तुलना भी शामिल है, ताकि == ऑपरेटर अधिभार के गतिशील/देर से बाध्य/प्रतिबिंब-आधारित आवेषण विफल नहीं होंगे।


अधिक जानकारी

पूर्वनिर्धारित मूल्य प्रकारों के लिए, समानता ऑपरेटर (==) TRUE देता अपने ऑपरेंड के मूल्यों अन्यथा बराबर, झूठे हैं। संदर्भ स्ट्रिंग के अलावा अन्य प्रकार के लिए, == सही होता है यदि उसके दो ऑपरेशंस को उसी ऑब्जेक्ट का संदर्भ देते हैं।स्ट्रिंग प्रकार के लिए, == तारों के मानों की तुलना करता है।

- http://msdn.microsoft.com/en-us/library/53k8ybth.aspx

आप क्या कहा तात्पर्य है कि == एक double की तुलना के लिए संदर्भ प्रकार अर्थ विज्ञान का उपयोग करता है। हालांकि, चूंकि double एक मान प्रकार है, यह मूल्य semantics का उपयोग करता है। यही कारण है कि 3 == 3 सच है, भले ही वे अलग-अलग स्टैक ऑब्जेक्ट्स हों।

आप लगभग कैसे LINQ के Queryable वस्तु शामिल विस्तार तरीकों उन में कोड के साथ के रूप में इस संकलक अनुवाद के बारे में सोच सकते हैं, लेकिन संकलक अभिव्यक्ति पेड़ जो LINQ प्रदाता के लिए बजाय पारित कर रहे हैं में इन कॉल अनुवाद करता है। दोनों मामलों में, अंतर्निहित कार्य वास्तव में कभी नहीं बुलाया जाता है।


डबल की तुलना अर्थ विज्ञान

डबल के लिए दस्तावेज़ कैसे ceq सीआईएल अनुदेश काम करता है का उल्लेख करने देता:

दो Double.NaN मूल्यों बराबर विधि को फोन करके समानता के लिए जांच की जाती है, तो विधि सच हो जाती है। हालांकि, यदि समानता ऑपरेटर का उपयोग करके समानता के लिए दो NaN मानों का परीक्षण किया जाता है, तो ऑपरेटर झूठी रिटर्न देता है। जब आप यह निर्धारित करना चाहते हैं कि डबल का मान एक संख्या (NaN) नहीं है, तो IsNaN विधि को कॉल करने का विकल्प है।

- http://msdn.microsoft.com/en-us/library/ya2zha7s.aspx


कच्चे संकलक स्रोत

आप decompiled सी # संकलक स्रोत में देखो, तो आप ceq में डबल तुलना की प्रत्यक्ष अनुवाद को संभालने के लिए निम्नलिखित कोड मिल जाएगा:

private void EmitBinaryCondOperator(BoundBinaryOperator binOp, bool sense) 
{ 
    int num; 
    ConstantValue constantValue; 
    bool flag = sense; 
    BinaryOperatorKind kind = binOp.OperatorKind.OperatorWithLogical(); 
    if (kind <= BinaryOperatorKind.GreaterThanOrEqual) 
    { 
     switch (kind) 
     { 
      ... 

      case BinaryOperatorKind.Equal: 
       goto Label_0127; 

      ... 
     } 
    } 
... 
Label_0127: 
    constantValue = binOp.Left.ConstantValue; 
    if (((constantValue != null) && constantValue.IsPrimitiveZeroOrNull) && !constantValue.IsFloating) 
    { 
     ... 
     return; 
    } 
    constantValue = binOp.Right.ConstantValue; 
    if (((constantValue != null) && constantValue.IsPrimitiveZeroOrNull) && !constantValue.IsFloating) 
    { 
     ... 
     return; 
    } 
    this.EmitBinaryCondOperatorHelper(ILOpCode.Ceq, binOp.Left, binOp.Right, sense); 
    return; 
} 

उपरोक्त कोड Roslyn.Compilers.CSharp.CodeGen.CodeGenerator.EmitBinaryCondOperator(...) से है, और मैंने इस उद्देश्य के लिए कोड को और अधिक पठनीय बनाने के लिए "..." जोड़ा है।

+1

अच्छा विस्तृत जवाब। तो अपनी प्रतिक्रिया को सारांशित करने के लिए, डबल :: op_equality ऑपरेटर का आह्वान किया जाता है लेकिन संकलक द्वारा इसके कार्यान्वयन के लिए 'इनलाइन' होता है यानी एक सीईसी ओपी कोड। प्रतिबिंबक गलत रूप से सीक्यू ओप कोड को == कॉल पर डिकंपलिंग कर रहा है। सही बात? – Gishu

+0

शब्दों की गलत पसंद-मेरी गलती। 'संदर्भ समानता' से मेरा क्या मतलब था कि एक ऑब्जेक्ट हमेशा अपने लिए == होना चाहिए। तो 'instance1 == instance1' लगभग सभी मामलों में सच है क्योंकि वे दोनों एक ही (refType/valueType) ऑब्जेक्ट को इंगित कर रहे हैं। (Double.Nan को छोड़कर - जो गणितीय कारणों के लिए नियम का अपवाद है) – Gishu

+0

@ गिशू परफेक्ट टीएल; डॉ संस्करण :) –

1

MSDN से: http://msdn.microsoft.com/en-us/library/ya2zha7s.aspx

दो Double.NaN मूल्यों बराबर विधि को फोन करके समानता के लिए जांच की जाती है, तो विधि सच देता है। हालांकि, यदि समानता ऑपरेटर का उपयोग करके समानता के लिए 0 Naका परीक्षण किया जाता है, तो ऑपरेटर झूठा देता है। जब आप यह निर्धारित करना चाहते हैं कि डबल का मान कोई संख्या (NaN) नहीं है, तो एक विकल्प IsNaN विधि को कॉल करना है।

2

msdn में यह कहा गया है कि;

यदि बराबर विधि को कॉल करके समानता के लिए दो डबल एनएएन मानों का परीक्षण किया जाता है, तो विधि सही होती है। हालांकि, यदि समानता ऑपरेटर का उपयोग करके समानता के लिए 0 Naका परीक्षण किया जाता है, तो ऑपरेटर झूठा देता है। जब आप यह निर्धारित करना चाहते हैं कि डबल का मान कोई संख्या (NaN) नहीं है, तो एक विकल्प IsNaN विधि को कॉल करना है।

यह आईईसी के अनुरूप 60559 delibaretly किया जाता है: 1989 के बाद से यह कहा गया है कि दो NaN मूल्यों के बराबर नहीं के रूप में वे संख्या के रूप में व्यवहार नहीं कर रहे हैं, तो op_Equal परिभाषा इस standart का पालन हो रहे हैं;

आईईसी 60559 के अनुसार: 1989, दो चल बिन्दु संख्या NaN के मूल्यों के साथ कभी नहीं equal.However, System.Object के लिए विशेष निर्देशों के अनुसार :: बराबर हैं विधि, यह वांछनीय है इस विधि ओवरराइड करने के लिए मूल्य समानता semantics प्रदान करने के लिए। सिस्टम के बाद से। ValueType प्रतिबिंब के उपयोग के माध्यम से इस कार्यक्षमता को प्रदान करता है, ऑब्जेक्ट के लिए विवरण। विशेष रूप से यह कहता है कि मूल्य प्रकार प्रदर्शन प्रदर्शन प्राप्त करने के लिए डिफ़ॉल्ट ValueType कार्यान्वयन को ओवरराइड करना चाहिए। वास्तव में सिस्टम के स्रोत को देखने से। ValueType :: एसएससीएलआई में clr \ src \ BCL \ System \ ValueType.cs की लाइन 36), सीएलआर परफ टीम से प्रभाव पर भी एक टिप्पणी है सिस्टम। वैल्यू टाइप :: बराबर नहीं है।

उल्लेख करने के लिए: http://blogs.msdn.com/b/shawnfa/archive/2004/07/19/187792.aspx

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