2015-07-15 7 views
7

इस तुलना का परिणाम मुझे (CPython 3.4) को हैरान कर दिया:9007199254740993 क्यों है! = 9007199254740993.0?

>>> 9007199254740993 == 9007199254740993.0 
False 

the docs की मेरी समझ है कि बाईं संकार्य सही संकार्य के प्रकार के मैच के लिए float लिए डाली जानी चाहिए:

पायथन पूरी तरह मिश्रित अंकगणितीय का समर्थन करता है: जब एक बाइनरी अंकगणितीय ऑपरेटर के पास विभिन्न संख्यात्मक प्रकारों का संचालन होता है, तो "नरक" प्रकार के साथ ऑपरेंड दूसरे की तरफ बढ़ जाता है, जहां पूर्णांक फ्लोटिंग पॉइंट से संकुचित होता है, जो जटिल से संकुचित होता है। मिश्रित प्रकार की संख्या के बीच तुलना एक ही नियम का उपयोग करें। कन्स्ट्रक्टर int(), फ्लोट(), और जटिल() का उपयोग किसी विशिष्ट प्रकार की संख्या के उत्पादन के लिए किया जा सकता है।

यह हो रहा हो प्रतीत नहीं होता:

>>> float(9007199254740993) == 9007199254740993.0 
True 

यहाँ क्या हो रहा है?

+3

ध्यान दें कि '9007199254740993.0' वास्तव में है' 9007199254740992.0' .. –

+0

दान के जवाब के आधार पर, आप की जाँच करके समानता के लिए परीक्षण कर सकते हैं और यदि '(9007199254740993-9007199254740993.0) == 0.0' (चूंकि '-' अनिवार्य रूप से एक अंकगणितीय ऑपरेटर है)। – larsks

+0

* क्यों * के लिए, http://stackoverflow.com/q/1848700/3001761 – jonrsharpe

उत्तर

7

पायथन बिल्कुल पूर्णांक को यहां एक फ्लोट में परिवर्तित नहीं करता है;

>>> 9007199254740993 == int(9007199254740993.0) 
False 

विफल रहता है ऐसा इसलिए है क्योंकि पूर्णांक (9007199254740993.0) वास्तव में 9007199254740992 है:

>>> 9007199254740992 == 9007199254740993.0 
True 

float_richcompare() function देखें कि यह एक पूर्णांक के लिए नाव बदल देता है। विशेष रूप से, यह पहले टिप्पणी:

/* Comparison is pretty much a nightmare. 

[...] 

* When mixing float with an integer type, there's no good *uniform* approach. 
* Converting the double to an integer obviously doesn't work, since we 
* may lose info from fractional bits. Converting the integer to a double 
* also has two failure modes: (1) an int may trigger overflow (too 
* large to fit in the dynamic range of a C double); (2) even a C long may have 
* more bits than fit in a C double (e.g., on a 64-bit box long may have 
* 63 bits of precision, but a C double probably has only 53), and then 
* we can falsely claim equality when low-order integer bits are lost by 
* coercion to double. So this part is painful too. 

क्या इन दो संख्याओं के लिए होता है यह है:

  • अजगर int.__eq__(float) मार्ग की कोशिश करता है, लेकिन वह NotImplemented
  • अजगर की कोशिश करता है float.__eq__(int) मार्ग, रिटर्न जो float_richcompare() संभालती है।

उस फ़ंक्शन में v आपकी फ्लोट है, w पूर्णांक है। निम्नलिखित उस पथ के लिए मार डाला है कोड की एक चयन है:

else if (PyLong_Check(w)) { /* true because the other number is an Python integer */ 

    /* ... */ 

    nbits = _PyLong_NumBits(w); /* 54 for your integer */ 

    /* ... */ 

    if (nbits <= 48) { /* nope, can't make it a float outright */ 
     /* ... */ 
    } 

    (void) frexp(i, &exponent); /* the exponent is 54 for your float */ 

    if (exponent < 0 || (size_t)exponent < nbits) { 
     /* not true */ 
    } 
    if ((size_t)exponent > nbits) { 
     /* also not true */ 
    } 
    /* v and w have the same number of bits before the radix 
    * point. Construct two ints that have the same comparison 
    * outcome. 
    */ 
    { 
     /* code to convert v to an integer vv, copy w to ww */ 

     r = PyObject_RichCompareBool(vv, ww, op); 

     /* ... */ 

     result = PyBool_FromLong(r); 

     /* ... */ 

     return result; 
    } 
अंत में आकार शामिल नंबरों की के कारण

तो, अजगर एक पूर्णांक के लिए नाव बदल देता है, और यह है कि रूपांतरण जहां है फ़्लोटिंग पॉइंट नंबर 9007199254740992 हो जाता है। ऐसा इसलिए है क्योंकि एक नाव वास्तव में 9007199254740993.0 व्यक्त नहीं कर सकते सही रूप में बताया गया है:

>>> 9007199254740993.0 
9007199254740992.0 
संबंधित मुद्दे