2013-07-22 4 views
6

क्या कोई इस छोटे कार्यक्रम के साथ क्या हो रहा है समझा सकता है?अंकगणितीय परिचालनों के साथ असमान प्रक्रिया समय [सी]

#include<stdio.h> 

int main() 
{ 
    float a=0.577; 
    float b=0.921; 
    float c; 
    int i; 

    for (i=0;i<100000000;i+=1){ 
     c=0.7*a-0.2*b; 
     //a=0.145*c+2.7*b; 
    } 

    printf ("%.3f\n",c); 
} 

नोट, एक पंक्ति टिप्पणी की गई है।

मैंने लाइन के बिना इसे पहले और फिर लाइन के साथ संकलित किया। (प्रयुक्त gcc -O2 ...)। और प्रसंस्करण समय मापा। मैं यह जानकर बहुत हैरान था कि निष्पादन समय 0.001s बनाम 2.444s था। और यह ज्यादा समझ में नहीं आता है। या इसके बजाय, इसके पीछे कुछ तर्क होना चाहिए।

क्या आप कृपया बता सकते हैं कि क्या हो रहा है और इस समस्या को कैसे कम किया जाए?

मैं ऐसे प्रोग्राम पर काम करता हूं जो बड़ी मात्रा में डेटा संसाधित करता है और ऐसा लगता है कि मैं वहां एक ही प्रदर्शन समस्या में भाग लेता हूं।

मैं फ्लोट से पूर्णांक में स्विच करने पर विचार कर रहा था लेकिन ऐसा लगता है कि पूर्णांक के साथ यह वही व्यवहार करता है।

संपादित करें: अंत में समाधान मामूली और तार्किक था। तो मैं सभी उत्तरों और स्पष्टीकरण के लिए धन्यवाद!

+0

क्या आपने जेनरेट किए गए कोड को देखा? –

+0

वैसे भी आप वास्तव में क्या कर रहे हैं? मुझे ऐसी निर्भरता श्रृंखला में कुछ सुधार करने के लिए बहुत कुछ नहीं दिख रहा है ... (कौन सा बीटीडब्ल्यू, बहुत तेज़ी से अभिसरण लगता है। मुझे लगता है कि उच्च पुनरावृत्ति गिनती सिर्फ इसे टेस्ट करने योग्य बनाने के लिए थी।) – Mysticial

+0

'ए' घोषित करने का प्रयास करें 'अस्थिर' के साथ। – jxh

उत्तर

13

पहले उदाहरण में गणना मूल्य स्थिर था। कंपाइलर c = 0.7 * 0.577 - 0.2 * 0.921संकलन समय पर गणना करेगा। यह लूप को अनुकूलित करने के लिए भी स्वतंत्र है क्योंकि इसमें कुछ भी नहीं बदलता है (a, b & c इनवेरिएंट हैं)।

दूसरे उदाहरण में, a और c प्रत्येक पुनरावृत्ति के लिए भिन्न होते हैं इसलिए 100000000 बार गणना की जानी चाहिए।

+0

हां। पहली पंक्ति में, सी बस संकलक द्वारा स्थिर करने के लिए सेट किया गया था। – Jiminion

+2

@Jim: नहीं, दूसरी पंक्ति स्थिर नहीं है। लूप के प्रत्येक पुनरावृत्ति पर, सी एक पर निर्भर करता है, और फिर सी पर निर्भर करता है। कुछ भी स्थिर नहीं है। –

+0

@ बिली, आप सही हैं। – Jiminion

2

टिप्पणी की गई लाइन के बिना, कंपाइलर पूरे पाश को अनुकूलित कर सकता है। लूप के संबंध में सेट किया जा रहा मान बदलता नहीं है।

टिप्पणी की गई लाइन के साथ, a का मान लूप की प्रत्येक शुरुआत में बदलता है, इसलिए लूप को अनुकूलित नहीं किया जा सकता है।

यही है, अपने कार्यक्रम और यह एक:

int main() 
{ 
    float a=0.577; 
    float b=0.921; 
    float c; 
    int i; 

    c=0.7*a-0.2*b; 
    for (i=0;i<100000000;i+=1){ 
     //a=0.145*c+2.7*b; 
    } 

    printf ("%.3f\n",c); 
} 

यदि और केवल यदि उस पंक्ति टिप्पणी की है एक ही जवाब का उत्पादन।

3

अच्छे अनुकूलक बहुत अच्छे हैं।

चूंकि एक-पंक्ति गणना प्रत्येक पुनरावृत्ति पर समान मान देती है, इसलिए लूप में कुछ भी पुन: गणना करने की आवश्यकता नहीं है, इसलिए अनुकूलक नहीं करता है।

जब आप a भी बदलते हैं (दो-पंक्ति गणना के साथ), तो उसे लूप को चलाना होगा।

इसलिए समय में अंतर।

2

यहाँ कोड मैं अनुकूलन के साथ अपने उदाहरण के संकलन से प्राप्त सक्षम है:

(__TEXT,__text) section 
_main: 
0000000100000f20 pushq %rbp 
0000000100000f21 movq %rsp, %rbp 
0000000100000f24 leaq 61(%rip), %rdi ## literal pool for: %.3f 

0000000100000f2b movsd 45(%rip), %xmm0 
0000000100000f33 movb $1, %al 
0000000100000f35 callq 0x100000f3e ## symbol stub for: _printf 
0000000100000f3a xorl %eax, %eax 
0000000100000f3c popq %rbp 
0000000100000f3d ret 

सूचना है कि पाश भी नहीं चलता है - संकलक इसे बाहर अनुकूलित किया है पूरी तरह से है, क्योंकि यह है कि केवल काम बता सकते हैं c की बात है कि यह मामला आखिरी है।

इसके विपरीत, टिप्पणी की लाइन के साथ पुनः लगाए, पाश चलाना चाहिए, और उत्पादन कोड की तरह दिखता है:

(__TEXT,__text) section 
_main: 
0000000100000ea0 pushq %rbp 
0000000100000ea1 movq %rsp, %rbp 
0000000100000ea4 movss 148(%rip), %xmm5 
0000000100000eac movl $100000000, %eax 
0000000100000eb1 movsd 143(%rip), %xmm1 
0000000100000eb9 movsd 143(%rip), %xmm2 
0000000100000ec1 movsd 143(%rip), %xmm3 
0000000100000ec9 movsd 143(%rip), %xmm4 
0000000100000ed1 nopw %cs:(%rax,%rax) 
0000000100000ee0 xorps %xmm0, %xmm0 
0000000100000ee3 cvtss2sd %xmm5, %xmm0 
0000000100000ee7 mulsd %xmm1, %xmm0 
0000000100000eeb addsd %xmm2, %xmm0 
0000000100000eef cvtsd2ss %xmm0, %xmm0 
0000000100000ef3 cvtss2sd %xmm0, %xmm0 
0000000100000ef7 movaps %xmm0, %xmm5 
0000000100000efa mulsd %xmm3, %xmm5 
0000000100000efe addsd %xmm4, %xmm5 
0000000100000f02 decl %eax 
0000000100000f04 cvtsd2ss %xmm5, %xmm5 
0000000100000f08 jne 0x100000ee0 
0000000100000f0a leaq 87(%rip), %rdi ## literal pool for: %.3f 

0000000100000f11 movb $1, %al 
0000000100000f13 callq 0x100000f1C## symbol stub for: _printf 
0000000100000f18 xorl %eax, %eax 
0000000100000f1a popq %rbp 
0000000100000f1b ret 

काफी अलग है, जैसा कि आप देख सकते हैं।

+0

यह मशीन + असेंबली कोड की तरह दिखता है। मैं इस कोड को जीसीसी पर कैसे प्राप्त कर सकता हूं? – haccks

+2

मैंने अपने मैक पर 'otool' का उपयोग करके बस अलग किया। यदि आप लिनक्स पर हैं तो आप 'objdump' का उपयोग कर सकते हैं। वैकल्पिक रूप से, संकलक स्वयं '-एस' ध्वज के साथ असेंबली उत्पन्न करेगा (हालांकि यह अक्सर कम पठनीय है)। –

+1

एक असेंबलर पहले ही असेंबली कोड को मशीन कोड में परिवर्तित कर देता है ... –

2

a=0.145*c+2.7*b; लाइन के साथ टिप्पणी की गई, आपके लूप के अंदर एकमात्र अभिव्यक्ति लूप-इनवेरिएंट है। आपका अनुकूलक जानता है कि, इसलिए यह लूप के बाहर गणना को स्थानांतरित करता है। फिर ऑप्टिमाइज़र नोटिस लूप में कुछ भी नहीं है, इसलिए यह लूप से छुटकारा पाता है।

जब आप लाइन को वापस रखते हैं, अभिव्यक्ति अब लूप-इनवेरिएंट नहीं है।

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