जैसा कि @Angew ने बताया , !=
ऑपरेटर को दोनों तरफ एक ही प्रकार की आवश्यकता होती है।
(float)i != i
आरएचएस को बढ़ावा देने के परिणाम भी तैरते हैं, इसलिए हमारे पास है (float)i != (float)i
।
जी ++ भी एक अनंत लूप उत्पन्न करता है, लेकिन यह इसके अंदर से काम को अनुकूलित नहीं करता है। आप यह देख सकते हैं कि यह अंतर-फ़्लोट के साथ परिवर्तित cvtsi2ss
होता ucomiss xmm0,xmm0
है और (float)i
स्वयं से तुलना करता है। (यह आपका पहला सुराग था कि आपके C ++ स्रोत का मतलब यह नहीं है कि आपने क्या सोचा था कि यह @ Angew का उत्तर बताता है।)
x != x
यह सच है जब यह "अनियंत्रित" x
था क्योंकि NaN था। ( INFINITY
IEEE गणित में खुद के बराबर की तुलना करता है, लेकिन NaN NAN == NAN
गलत नहीं है, NAN != NAN
सच है)।
gcc7.4 और पुराने अपने कोड को jnp
लूप शाखा ( https://godbolt.org/z/fyOhW1 ) के रूप में सही रूप से अनुकूलित करता है : जब तक ऑपरेशंस x != x
NaN नहीं होते तब तक लूपिंग को चालू रखें । (gcc8 और बाद je
में लूप से ब्रेक आउट की जाँच करता है, इस तथ्य के आधार पर अनुकूलन करने में विफल कि यह किसी भी गैर-NaN इनपुट के लिए हमेशा सही रहेगा)। x86 FP अनियंत्रित पर सेट पीएफ की तुलना करता है।
और BTW, इसका मतलब है कि क्लैंग का ऑप्टिमाइज़ेशन भी सुरक्षित है : इसे बस CSE (float)i != (implicit conversion to float)i
के समान होना चाहिए, और यह साबित करना चाहिए कि i -> float
संभव सीमा के लिए कभी भी NaN नहीं है int
।
(हालांकि यह देखते हुए कि यह लूप हस्ताक्षरित-अतिप्रवाह यूबी को हिट करेगा, यह शाब्दिक रूप से किसी भी तरह का कोई भी ud2
निर्देश, जिसमें कोई अवैध निर्देश, या लूप बॉडी वास्तव में क्या था, की परवाह किए बिना एक खाली अनंत लूप को बाहर निकालने की अनुमति है ।) लेकिन हस्ताक्षरित-अतिप्रवाह यूबी की अनदेखी करना। , यह अनुकूलन अभी भी 100% कानूनी है।
GCC लूप बॉडी को ऑप्टिमाइज़ करने में भी नाकाम है, यहां तक कि -fwrapv
हस्ताक्षरित-पूर्णांक ओवरफ्लो को अच्छी तरह से परिभाषित करने के लिए भी (2 के पूरक रैपराउंड के रूप में)। https://godbolt.org/z/t9A8t_
यहां तक कि सक्षम करने से -fno-trapping-math
भी मदद नहीं मिलती है। (GCC का डिफ़ॉल्ट दुर्भाग्य से सक्षम करने के लिए है,
-ftrapping-math
भले ही GCC का क्रियान्वयन टूटा / छोटा हो ।) int-> फ्लोट रूपांतरण के कारण FP अक्षम्य अपवाद हो सकता है (संख्याओं का बहुत बड़ा प्रतिनिधित्व किया जा सकता है), इसलिए अपवादों के साथ संभवत: यह अस्वीकार्य नहीं है। लूप बॉडी को ऑप्टिमाइज़ करें। (क्योंकि 16777217
फ्लोट में कनवर्ट करने पर ऑब्जर्वेबल साइड-इफ़ेक्ट हो सकता है, अगर एक्सपेक्ट अपवाद अपवाद नहीं है।)
लेकिन इसके साथ -O3 -fwrapv -fno-trapping-math
, यह 100% छूट वाला अनुकूलन है जो इसे खाली अनंत लूप में संकलित नहीं करता है। बिना #pragma STDC FENV_ACCESS ON
, चिपचिपा झंडे की स्थिति जो कि एफपी अपवादों को रिकॉर्ड करती है, कोड का एक नमूदार साइड-इफेक्ट नहीं है। नहीं int
-> float
रूपांतरण का परिणाम NaN हो x != x
सकता है , इसलिए यह सच नहीं हो सकता।
ये संकलनकर्ता C ++ कार्यान्वयन के लिए सभी अनुकूलन कर रहे हैं जो IEEE 754 एकल-परिशुद्धता (बाइनरी float
32 ) और 32-बिट का उपयोग करते हैं int
।
Bugfixed(int)(float)i != i
पाश संकीर्ण 16-बिट के साथ सी ++ कार्यान्वयन पर यूबी होता int
और / या व्यापक float
क्योंकि आप हिट हैं, पर हस्ताक्षर किए-पूर्णांक अतिप्रवाह यूबी पहले पूर्णांक है कि एक के रूप में वास्तव में प्रदर्शनीय नहीं था तक पहुँचने से पहले float
।
लेकिन कार्यान्वयन-परिभाषित विकल्पों के एक अलग सेट के तहत UB को x86-64 सिस्टम V ABI के साथ gcc या क्लैंग जैसे कार्यान्वयन के लिए संकलन करते समय कोई नकारात्मक परिणाम नहीं होता है।
BTW, आप सांख्यिकीय रूप से इस लूप के परिणाम की गणना कर सकते हैं FLT_RADIX
और FLT_MANT_DIG
, में परिभाषित किया गया है <climits>
। या कम से कम आप सिद्धांत में कर सकते हैं, अगर float
वास्तव में एक आईईईई फ्लोट के मॉडल को फिट करता है बजाय किसी अन्य प्रकार के वास्तविक संख्या प्रतिनिधित्व जैसे कि पॉसिट / अनम।
मुझे यकीन नहीं है कि float
व्यवहार के बारे में आईएसओ सी ++ मानक नाखून कितना नीचे है और क्या एक प्रारूप जो निश्चित-चौड़ाई वाले घातांक और महत्व के क्षेत्रों पर आधारित नहीं था, मानकों के अनुरूप होगा।
टिप्पणियों में:
@geza मुझे परिणामी संख्या सुनने में दिलचस्पी होगी!
@ नदा: यह 16777216 है
क्या आप दावा कर रहे हैं कि आपको यह लूप प्रिंट करने / वापस करने के लिए मिला है 16777216
?
अपडेट: चूंकि वह टिप्पणी हटा दी गई है, मुझे नहीं लगता। संभवतः ओपी float
पहले पूर्णांक से पहले उद्धृत कर रहा है जिसे 32-बिट के रूप में बिल्कुल प्रतिनिधित्व नहीं किया जा सकता है float
। https://en.wikipedia.org/wiki/Single-preaches_floating-point_format#Preults_limits_on_integer_values यानी वे इस छोटी गाड़ी के कोड के साथ सत्यापन की उम्मीद कर रहे थे।
Bugfixed संस्करण निश्चित रूप से प्रिंट होगा 16777217
, पहला पूर्णांक जो कि इससे पहले मूल्य के बजाय, बिल्कुल प्रतिनिधित्व योग्य नहीं है।
(सभी उच्च फ़्लोट मान सटीक पूर्णांक होते हैं, लेकिन वे 2 से 4 के गुणक होते हैं, फिर महत्व चौड़ाई से अधिक घातांक मान के लिए 4, 8 आदि। कई उच्च पूर्णांक मानों का प्रतिनिधित्व किया जा सकता है, लेकिन अंतिम स्थान पर 1 इकाई। (महत्व का) 1 से अधिक है, इसलिए वे सन्निहित पूर्णांक नहीं हैं। सबसे बड़ा परिमित float
2 ^ 128 से नीचे है, जो कि बहुत बड़ा है int64_t
।)
यदि कोई कंपाइलर मूल लूप से बाहर निकलता है और प्रिंट करता है, तो वह कंपाइलर बग होगा।