2010-08-16 21 views
7

को देखते हुए निम्नलिखित स्निपेट:लंबे बनाम पूर्णांक गुणन

#include <stdio.h> 

typedef signed long long int64; 
typedef signed int int32; 
typedef signed char int8; 

int main() 
{ 
    printf("%i\n", sizeof(int8)); 
    printf("%i\n", sizeof(int32)); 
    printf("%i\n", sizeof(int64)); 

    int8 a = 100; 
    int8 b = 100; 
    int32 c = a * b; 
    printf("%i\n", c); 

    int32 d = 1000000000; 
    int32 e = 1000000000; 
    int64 f = d * e; 
    printf("%I64d\n", f); 
} 

MinGW जीसीसी 3.4.5 के साथ उत्पादन होता है (-O0):

1 
4 
8 
10000 
-1486618624 

पहले गुणा एक int32 को आंतरिक रूप से casted है (असेंबलर आउटपुट के अनुसार)। दूसरा गुणा नहीं किया जाता है। मुझे यकीन नहीं है कि परिणाम भिन्न हैं क्योंकि प्रोग्राम आईए 32 पर चल रहा था, या क्योंकि इसे सी मानक में कहीं परिभाषित किया गया है। फिर भी मुझे दिलचस्पी है कि अगर यह सटीक व्यवहार कहीं परिभाषित किया गया है (आईएसओ/आईईसी 98 99?), क्योंकि मुझे बेहतर समझना अच्छा लगता है कि मुझे मैन्युअल रूप से क्यों डालना है (मुझे एक अलग वास्तुकला से प्रोग्राम को पोर्ट करने में समस्याएं हैं)।

उत्तर

7

C99 मानक निर्दिष्ट करता है कि इस तरह के * के रूप में द्विआधारी ऑपरेटरों int की तुलना में छोटे पूर्णांक प्रकार पर काम नहीं करते। ऑपरेटर लागू होने से पहले इन प्रकारों के अभिव्यक्ति को int पर प्रचारित किया जाता है। 6.3.1.4 अनुच्छेद 2 और "पूर्णांक पदोन्नति" शब्दों की कई घटनाएं देखें। लेकिन यह संकलक द्वारा उत्पन्न असेंबली निर्देशों के लिए कुछ हद तक ऑर्थोगोनल है, जो int एस पर काम करता है क्योंकि यह तब भी तेज होता है जब संकलक को कम परिणाम की गणना करने की अनुमति दी जाती है (क्योंकि परिणाम तुरंत एक छोटे से एल-वैल्यू में संग्रहीत होता है उदाहरण के लिए टाइप करें)।

के बारे में int64 f = d * e; जहां d और e प्रकार int के हैं, गुणन ही पदोन्नति नियमों के अनुसार एक int के रूप में किया जाता है। ओवरफ्लो तकनीकी रूप से अपरिभाषित व्यवहार है, आपको यहां दो-पूरक पूरक परिणाम मिल रहे हैं, लेकिन आप मानक के अनुसार कुछ भी प्राप्त कर सकते हैं।

नोट: पदोन्नति नियम प्रचार करते समय हस्ताक्षरित और हस्ताक्षरित प्रकारों को अलग करते हैं। नियम int तक छोटे प्रकारों को बढ़ावा देना है जब तक int इस प्रकार के सभी मानों का प्रतिनिधित्व नहीं कर सकता है, जिसमें unsigned int का उपयोग किया जाता है।

5

समस्या यह है कि गुणा int32 * int32 है, जो int32 के रूप में किया जाता है, और इसके परिणामस्वरूप एक int64 को असाइन किया जाता है। आपको double d = 3/2; के साथ बहुत अधिक प्रभाव मिलेगा, जो पूर्णांक विभाजन का उपयोग करके 3 से 2 को विभाजित करेगा, और 1.0 से d असाइन करेगा।

जब भी कोई फर्क पड़ता है तो आपको अभिव्यक्ति या उप-अभिव्यक्ति के प्रकार पर ध्यान देना होगा। यह सुनिश्चित करने के लिए उचित ऑपरेशन की गणना उचित प्रकार के रूप में की जाती है, जैसे कि मल्टीप्लिकैंड्स में से एक को int64 में कास्टिंग करना, या (मेरे उदाहरण में) 3.0/2 या (float)3/2

+1

बहुत अच्छी तरह से डाल दिया। @azraiyl को उस पंक्ति को 'int64 f = (int64) d * e; ' –

+0

में बदलना चाहिए क्षमा करें कि मैंने यह नहीं कहा है कि मुझे यहां समाधान पता है। मुझे क्या दिलचस्पी है, क्यों पहले मामले में गुणा int32 * int32 है और int8 * int8 नहीं है। यहां तक ​​कि यदि सीपीयू केवल int32 गुणा का समर्थन करता है तो गुणा के बाद इसे int8 पर वापस जाया जा सकता है। लेकिन IA32 imul निर्देश 8-बिट रजिस्टरों (AL, ...) के लिए काम करता है। – azraiyl

+0

@azrayl: कम से कम C90 में, सी ने सभी अंकगणितीय ऑपरेटरों को 'int' में प्रचारित किया, यदि वे छोटे प्रकार के थे। सी 99 मानक में एक नज़र से पता चलता है कि यह अब मामला नहीं है, लेकिन मुझे सच में यकीन नहीं है। आप किस सी संकलक का उपयोग कर रहे हैं, और यदि लागू हो, तो कौन से विकल्प हैं? –

2

a * b एक पूर्णांक के रूप में गणना की जाती है, और उसके बाद प्राप्त वैरिएबल प्रकार के साथ ढाले

d * e एक पूर्णांक के रूप में गणना की जाती है, और उसके बाद प्राप्त वैरिएबल प्रकार के साथ ढाले (जो सिर्फ होता है (जो सिर्फ पूर्णांक होना करने के लिए होता है) int64 होने के लिए)

यदि किसी प्रकार का चर बड़ा होता है तो उस प्रकार की तुलना में एक int (या फ़्लोटिंग पॉइंट) होता है। लेकिन चूंकि गुणाओं में उपयोग किए जाने वाले सभी प्रकार int या छोटे थे, इनट का उपयोग किया जाता था।

2

पढ़ें & आर (मूल) पढ़ें। सभी पूर्णांक ऑपरेशंस प्राकृतिक पूर्णांक प्रकार के साथ किए जाते हैं जब तक कि इसमें वेरिएबल शामिल नहीं होते हैं (या जाली जाती हैं) कुछ बड़ी होती हैं। चार पर ऑपरेशन 32 बिट्स पर डाले जाते हैं क्योंकि यह उस वास्तुकला पर पूर्णांक का प्राकृतिक आकार है। दो 32 बिट पूर्णांक का गुणा 32 बिट्स में किया जाता है क्योंकि कुछ भी इसे किसी भी चीज़ पर कास्टिंग नहीं कर रहा है (जब तक आप इसे 64 बिट वैरिएबल तक असाइन नहीं करते हैं, लेकिन यह बहुत देर हो चुकी है)। यदि आप 64 बिट्स में ऑपरेशन करना चाहते हैं, तो एक या दोनों चींटियों को 64 बिट्स पर डालें।

int64 f = (int64)d * e; 
संबंधित मुद्दे