2010-01-12 9 views
12

मैं दृढ़ता और सुसंगतता के लिए निरंतर अभिव्यक्तियों के गणित कार्यों का उपयोग करता हूं (log(x)/0.3... के बजाय log(x)/log(2))। चूंकि ये फ़ंक्शंस वास्तव में भाषा का हिस्सा नहीं हैं, न ही उन्हें math.h (केवल घोषित) में परिभाषित किया गया है, क्या स्थिरांक संकलित समय पर सटीक हो जाएंगे, या क्या उन्हें रनटाइम पर कथित रूप से गणना की जाएगी?निरंतर अभिव्यक्तियों के गणित कार्यों को संकलित समय पर पूर्व-गणना की जाती है?

+0

मुझे उम्मीद है कि वे सटीक हो जाएंगे, लेकिन अगर आपने कहा कि आप किस कंपाइलर का उपयोग कर रहे थे तो इससे मदद मिलेगी ताकि लोग वास्तव में जांच सकें। – Hazior

+1

लॉग (एक्स), ज़ाहिर है, संकलन समय पर निरंतर अभिव्यक्ति नहीं है, जब तक कि x को पहले स्थिर नहीं किया गया हो और मान दिया जाए। शायद कोड लिखना बहुत मुश्किल नहीं है, जो किसी भी कंपाइलर का मूल्यांकन नहीं करेगा, भले ही मानव के लिए ऐसा करना आसान हो। –

+0

जब से मैं इसमें भाग गया, यह लंबे समय से रहा है, लेकिन ऐसे कार्यान्वयन हुए हैं जो फ्लोटिंग-पॉइंट गणनाओं के कुछ विवरण रनटाइम पर निर्दिष्ट किए जाने की अनुमति देते हैं। उस स्थिति में, इसके आधार पर कुछ भी संकलन समय पर गणना नहीं की जा सकती है। –

उत्तर

10

कुछ कंपाइलर्स संकलन समय पर उनका मूल्यांकन करेंगे, लेकिन इस व्यवहार की गारंटी नहीं है (और ऐसा करने से समस्याएं भी हो सकती हैं)। आपको अपने कंपाइलर को जांचना होगा और देखें कि यह क्या करता है।

ध्यान दें कि कई प्रणालियों पर log(2)<math.h> में मैक्रो M_LN2 से उपलब्ध है।

+2

यदि संकलक जानता है कि लॉग का कोई दुष्प्रभाव नहीं है और हमेशा एक ही मान देता है (उदाहरण के लिए, एक 'शुद्ध' फ़ंक्शन है), तो यह संकलन समय पर उनका मूल्यांकन कर सकता है। चूंकि उपयोगकर्ता के पास गणित लाइब्रेरी से फ़ंक्शंस को बदलने का विकल्प होता है और लॉग को उस फ़ंक्शन के साथ प्रतिस्थापित करना चुन सकता है जो प्रत्येक बार लॉग (2) के लिए समान मान वापस नहीं करता है या उसके दुष्प्रभाव होते हैं, तो संकलक मूल्यांकन नहीं कर सकता यह संकलन समय पर। –

+1

परिणाम सही होने पर मैं इस व्यवहार को सख्त मोड में दो अलग-अलग कंपाइलर्स (जीसीसी, आईसीसी) पर प्राप्त करने में सक्षम हूं (उदाहरण के लिए 'पाउ (2.0, 2.0) ') और इसलिए कॉल (सिद्धांत में) साइड-इफेक्ट मुक्त है इस धारणा के तहत कि उपयोगकर्ता ने अपना खुद का दिनचर्या नहीं बदला है। जबकि मैं आपके विश्लेषण से सहमत हूं कि संकलक शायद ऐसा नहीं कर रहे हैं, वे वैसे भी ऐसा करने के लिए पूरी तरह तैयार हैं = /। यह मुझे आश्चर्य नहीं करेगा अगर कुछ कंपाइलर झंडे प्रभावित होने पर भी ऐसा करते हैं, क्योंकि कंपाइलर लेखकों के पास आमतौर पर फ़्लोटिंग पॉइंट स्टेटस का एक बहुत ही मंद दृश्य होता है। –

+1

इसकी अनुमति है क्योंकि किसी भी मानक फ़ंक्शंस को प्रतिस्थापित करने का प्रयास करने वाले प्रोग्राम अब सी प्रोग्राम का पालन नहीं कर रहे हैं। – caf

3

वे आम तौर पर रनटाइम पर गणना करेंगे (उन्हें इनलाइन करने के तरीके के लिए अन्य उत्तरों देखें), हालांकि मैं तब तक "कचरा" शब्द का उपयोग नहीं करता जब तक कि उनमें से बहुत से नहीं थे और/या कोड को बहुत से निष्पादित किया गया था कई बार

बल्कि सिर्फ निरंतर मूल्य में डाल से, एक #define या const चर कि व्यक्त करता है क्या है कि बजाय मूल्य का अर्थ है (PI, LOG_2, आदि) और उपयोग पैदा करते हैं।

उदाहरण के लिए:

#define LOG_2 0.30102999566 

यह किसी भी गणना नहीं करता है और आप क्या कभी सटीक आप की इच्छा या अपने पर्यावरण (32 बिट वी 64 बिट) दिए गए प्रबंधित कर सकते हैं करने के लिए मान निर्दिष्ट कर सकते हैं।

+3

सावधान! यदि आप LOG_2 (लॉग (2)) '' निर्धारित करते हैं, तो ''LOG_2' का उपयोग करते समय' लॉग() 'कॉल करता है। एक 'कॉन्स' ग्लोबल वैरिएबल एक * बहुत * बेहतर विचार है। –

+1

@ माइक - मैं आपको यह सुझाव नहीं दे रहा था कि आप ऐसा करते हैं लेकिन # LOG_2 0.30102999' (या आप कितने डीपी चाहते हैं) – ChrisF

+1

आप गलत तरीके से दावा कर रहे हैं कि कम से कम जीसीसी के साथ उन्हें संकलन समय पर गणना की जाती है । – fortran

0

यह रनटाइम पर होता है क्योंकि फ़ंक्शन के लिए कोड केवल लिंकिंग चरण के दौरान उपलब्ध होता है (जो संकलन चरण के बाद होता है)।

चरण को अनुकूलित करने के लिए, वैश्विक वैरिएबल का उपयोग करें जिसका उपयोग आप इसे करने से पहले शुरू करते हैं।

+1

सिवाय इसके कि यदि यह एक मानक मानक हेडर में घोषित मानक फ़ंक्शन है, तो कार्यान्वयन इसके बारे में जानता है। –

+0

आप गलत हैं: यह जानता है कि फ़ंक्शन * मौजूद है * लेकिन इसका मतलब यह नहीं है कि मानक शीर्षलेख फ़ाइलों में घोषित कार्यों को कोई विशेष उपचार मिलता है। कंपाइलर के दृष्टिकोण से, वे किसी अन्य शीर्ष फ़ाइल से किसी भी अन्य फ़ंक्शन की तरह हैं। साथ ही, संकलक लिंक नहीं कर सकता है इसलिए किसी भी फ़ंक्शन को लोड करने और निष्पादित करने का कोई तरीका नहीं है, मानक या नहीं। –

3

यह निर्भर करता है। यदि संकलक गणित को ठीक से कर सकता है क्योंकि यह रनटाइम पर किया जाएगा, और यदि लिंक समय अनुकूलन किया जाता है, और यदि पुस्तकालय किसी प्रकार के मध्यवर्ती रूप में रखा जाता है, तो हाँ यह किया जा सकता है।

अधिकांश कंपाइलर ऐसा नहीं करते हैं।

3

लाइब्रेरी फ़ंक्शंस के मामले में, कुछ कंपाइलर इन कार्यों को इंट्रिनिक्स के रूप में कार्यान्वित कर सकते हैं, जिसका अर्थ है कि संकलक कॉल को प्रतिस्थापित करने के लिए कॉल को प्रतिस्थापित करने के कार्यों के बारे में पर्याप्त जानता है। चाहे वह ऐसा करेगा, संकलक पर निर्भर करता है। व्यावहारिक रूप से, मैं अक्सर ध्यान देता हूं कि कुछ कंपाइलर संकलन समय पर फ़्लोटिंग-पॉइंट एक्सप्रेशन की पूर्व-गणना करने के लिए अनिच्छुक हैं, भले ही उनमें कोई फ़ंक्शन कॉल शामिल न हो।

सामान्य स्थिति में, आम तौर पर संकलन समय पर गणना नहीं की जाएगी और गणना नहीं की जा सकती है, यह मानते हुए कि संकलक बस इन कार्यों के बारे में पर्याप्त नहीं जानता है ताकि संकलन समय पर उनकी गणना कर सकें। हो सकता है कि उनके पास कुछ प्रमुख रन-टाइम दुष्प्रभाव हों?

कुछ कंपाइलरों में गैर-मानक कंपाइलर-निर्भर एक्सटेंशन हो सकते हैं जो उपयोगकर्ता को कंपाइलर के कार्यों के बारे में अतिरिक्त जानकारी प्रदान करने की अनुमति देते हैं, ताकि संकलक फ़ंक्शन कॉल को बेहतर तरीके से अनुकूलित कर सके और यह भी पता लगाए कि किसी दिए गए कॉल को प्रतिस्थापित किया जा सकता है या नहीं एक संकलन समय पूर्व गणना के साथ। उदाहरण के लिए, जीसीसी कंपाइलर attributes (जीसीसी-विशिष्ट एक्सटेंशन) const और pure जैसे फ़ंक्शन का समर्थन करता है।यदि तर्क संकलन समय पर ज्ञात हैं, तो const विशेषता के साथ कार्य करने के लिए कॉल को सैद्धांतिक रूप से संकलित-समय पूर्व-गणना के साथ प्रतिस्थापित किया जा सकता है। हालांकि मैं यह नहीं कह सकता कि जीसीसी वास्तव में ऐसा कर सकता है या नहीं।

सी ++ में (भले ही आपका प्रश्न टैग किया गया हो) भाषा एक योजनाबद्ध नई सुविधा constexpr घोषणा विनिर्देशक है जो एक समान उद्देश्य प्रदान करता है और आपके द्वारा वर्णित प्रभाव का अनुमान लगाया जाता है।

16

यह कंपाइलर और अनुकूलन झंडे पर निर्भर करता है।

$ cat constant_call_opt.c 
#include <math.h> 

float foo() { 
     return log(2); 
} 

$ gcc -c constant_call_opt.c -S 

$ cat constant_call_opt.s 
     .file "constant_call_opt.c" 
     .text 
.globl foo 
     .type foo, @function 
foo: 
     pushl %ebp 
     movl %esp, %ebp 
     subl $4, %esp 
     movl $0x3f317218, %eax 
     movl %eax, -4(%ebp) 
     flds -4(%ebp) 
     leave 
     ret 
     .size foo, .-foo 
     .ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3" 
     .section  .note.GNU-stack,"",@progbits 

नहीं: @AndrewyT बताते हैं, जीसीसी निर्दिष्ट करने के लिए जो कार्य करता है लगातार और विशेषताओं के माध्यम से शुद्ध कर रहे हैं, और इस मामले जवाब सकारात्मक है, यह परिणाम इनलाइन जाएगा, जैसा कि आप आसानी से देख सकते क्षमता है फ़ंक्शन कॉल, बस एक स्थिर लोड करता है (0x3f317218 == 0.69314718246459961 == log(2))

एल्थॉट मेरे पास अब कोशिश करने के लिए कोई अन्य कंपाइलर नहीं है, मुझे लगता है कि आप सभी प्रमुख सी कंपाइलरों में वही व्यवहार की उम्मीद कर सकते हैं, क्योंकि यह एक छोटा सा अनुकूलन है ।

+1

यदि आप अपने सिर में 0x3f317218 जैसे 32-बिट आईईईई फ़्लोटिंग पॉइंट एन्कोडिंग को तत्काल डीकोड नहीं कर सकते हैं, तो 'लॉग (1.0)' को संकलित करने का प्रयास करें, जिसके परिणामस्वरूप 'movl $ 0x0,% eax' में अच्छा आसान स्थिर' $ 0x0' होता है। लाइन। –

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