मानक C ++ पुस्तकालयों में `int pow (इंट बेस, इंट एक्सपोनेंट) क्यों नहीं है?


116

मुझे लगता है कि मुझे इसे खोजने में असमर्थ होना चाहिए। क्या कोई कारण है कि सी ++ powफ़ंक्शन floatएस और doubleएस को छोड़कर किसी भी चीज़ के लिए "पावर" फ़ंक्शन को लागू नहीं करता है ?

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


4
यह एक अच्छा सवाल है, और मुझे नहीं लगता कि जवाब बहुत मायने रखते हैं। नकारात्मक घातांक काम नहीं करते? एक्सपोजर के रूप में अहस्ताक्षरित इनट्स लें। अधिकांश इनपुट इसे अतिप्रवाह का कारण बनाते हैं? एक्सप एंड डबल पॉव के लिए भी यही सच है, मैं किसी को भी शिकायत करते नहीं देखता। तो यह फ़ंक्शन मानक क्यों नहीं है?
स्थिर_पृथ्वी

2
@static_rtti: "एक्सप एंड डबल पॉ के लिए वही सच है" पूरी तरह से गलत है। मैं अपने उत्तर में विस्तार से बताऊंगा।
स्टीफन कैनन

11
मानक C ++ लाइब्रेरी में double pow(int base, int exponent)C ++ 11 (.826.8 [c.math] / 11 बुलेट पॉइंट 2) के बाद से है
Cubbi

आपको 'कार्यान्वयन तुच्छ है' और 'लिखने में मज़ा नहीं' के बीच अपना दिमाग बनाने की ज़रूरत है।
लोर्न

जवाबों:


66

चूंकि C++11विशेष मामलों को पावर फ़ंक्शंस (और अन्य) के सूट में जोड़ा गया था। C++11 [c.math] /11राज्यों, सभी float/double/long doubleअधिभार (मेरा जोर, और पैराफ्रेस्ड) को सूचीबद्ध करने के बाद :

इसके अलावा, यह सुनिश्चित करने के लिए पर्याप्त अतिरिक्त अधिभार होगा कि, यदि किसी doubleपैरामीटर के अनुरूप कोई तर्क टाइप doubleया पूर्णांक प्रकार है, तो doubleपैरामीटर के अनुरूप सभी तर्क प्रभावी रूप से डाले जाते हैं double

इसलिए, मूल रूप से, पूर्णांक मापदंडों को ऑपरेशन करने के लिए डबल्स में अपग्रेड किया जाएगा।


इससे पहले C++11(जो कि आपका प्रश्न पूछा गया था), कोई पूर्णांक अधिभार मौजूद नहीं था।

चूँकि मैं न तो उनके निर्माण के दिनों में (न ही मैं पुराना हूँ ) Cन ही रचनाकारों के साथ घनिष्ठता से जुड़ा था , न ही ANSI / ISO समितियों का हिस्सा, जिन्होंने मानकों का निर्माण किया, यह आवश्यक रूप से मेरी ओर से राय है। मुझे लगता है कि यह सूचित राय है लेकिन, जैसा कि मेरी पत्नी आपको बताएगी (बार-बार और बहुत प्रोत्साहन के बिना आवश्यक), मैं पहले भी गलत रहा हूं :-)C++

आपूर्ति, इसके लायक क्या है, इस प्रकार है।

मुझे संदेह है कि मूल पूर्व-एएनएसआई के Cकारण यह सुविधा नहीं थी क्योंकि यह पूरी तरह से अनावश्यक था। सबसे पहले, पूर्णांक शक्तियों (डबल्स के साथ और फिर बस एक पूर्णांक में वापस परिवर्तित करने, पूर्णांक ओवरफ़्लो करने और परिवर्तित करने से पहले अंडरफ़्लो की जाँच) करने का एक अच्छा तरीका था।

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

चूंकि इसके प्रारंभिक उपयोग के मामलों में से एक को यूनिक्स को कोड करना था, इसलिए फ्लोटिंग पॉइंट बेकार हो जाएगा। BCPL, जिस पर C आधारित था, का भी शक्तियों के लिए कोई उपयोग नहीं था (इसमें मेमोरी से फ्लोटिंग पॉइंट बिल्कुल नहीं था)।

एक तरफ के रूप में, एक अभिन्न शक्ति ऑपरेटर संभवतः एक पुस्तकालय कॉल के बजाय एक द्विआधारी ऑपरेटर होगा। आप लाइब्रेरी के बजाय भाषा के भाग के x = add (y, z)साथ दो पूर्णांक नहीं जोड़ते हैं ।x = y + z

तीसरा, चूंकि अभिन्न शक्ति का कार्यान्वयन अपेक्षाकृत तुच्छ है, इसलिए यह लगभग निश्चित है कि भाषा के डेवलपर्स बेहतर समय प्रदान करने के लिए अपने समय का बेहतर उपयोग करेंगे (अवसर लागत पर टिप्पणी नीचे देखें)।

यह भी मूल के लिए प्रासंगिक है C++। चूंकि मूल कार्यान्वयन प्रभावी रूप से सिर्फ एक अनुवादक था जो Cकोड का उत्पादन करता था , इसने कई विशेषताओं को आगे बढ़ाया C। इसका मूल आशय C-with-classes था, C-with-classes-plus-a-little-bit-of-extra-math-stuff।

जैसा कि पहले कभी मानकों में क्यों नहीं जोड़ा गया था C++11, आपको याद रखना होगा कि मानकों-सेटिंग निकायों के पास विशिष्ट दिशानिर्देशों का पालन करना है। उदाहरण के लिए, एएनएसआई Cको विशेष रूप से मौजूदा अभ्यास को संहिताबद्ध करने का काम सौंपा गया था, कि एक नई भाषा बनाने के लिए। अन्यथा, वे पागल हो सकते थे और हमें आडा दिया :-)

उस मानक के बाद के पुनरावृत्तियों में भी विशिष्ट दिशा-निर्देश हैं और औचित्य दस्तावेजों में पाया जा सकता है (तर्क के रूप में क्यों समिति ने कुछ निर्णय लिए, न कि भाषा के लिए औचित्य)।

उदाहरण के लिए C99औचित्य दस्तावेज विशेष रूप से C89मार्गदर्शक सिद्धांतों में से दो को आगे बढ़ाता है जो कि सीमा में जोड़े जा सकते हैं:

  • भाषा को छोटा और सरल रखें।
  • ऑपरेशन करने के लिए केवल एक ही तरीका प्रदान करें।

व्यक्तिगत कामकाजी समूहों के लिए दिशानिर्देश (जरूरी नहीं कि वे विशिष्ट हों ) निर्धारित किए जाएं और इसलिए C++समितियों (और अन्य सभी आईएसओ समूहों) को भी सीमित करें ।

इसके अलावा, मानकों की स्थापना करने वाले निकायों को एहसास होता है कि उनके द्वारा किए गए प्रत्येक निर्णय के लिए एक अवसर लागत (एक आर्थिक शब्द का अर्थ है कि आपको क्या निर्णय लेना है)। उदाहरण के लिए, लगभग $ छह महीने के लिए उस $ 10,000 यूबर-गेमिंग मशीन को खरीदने का अवसर लागत सौहार्दपूर्ण संबंध (या शायद सभी संबंध) है।

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

दूसरे शब्दों में, क्या आपके पास एक अभिन्न पावर ऑपरेटर होगा (जो, ईमानदारी से, कोई भी आधा-सभ्य कोडर दस मिनट में कोड़ा कर सकता है) या मल्टी-थ्रेडिंग को मानक में जोड़ा जा सकता है? अपने आप के लिए, मैं बाद वाले को पसंद करूंगा और यूनिक्स और विंडोज के तहत अलग-अलग कार्यान्वयनों के बारे में नहीं सोचना चाहिए।

मैं मानक पुस्तकालय (हैश, बीट्रीस, लाल-काले पेड़, शब्दकोश, मनमाना नक्शे और इसके आगे) के हजारों और हजारों संग्रह भी देखना चाहता हूं, लेकिन साथ ही साथ, राज्यों में भी:

एक मानक कार्यान्वयनकर्ता और प्रोग्रामर के बीच एक संधि है।

और मानक निकायों पर कार्यान्वयनकर्ताओं की संख्या प्रोग्रामर की संख्या को दूर करती है (या कम से कम उन प्रोग्रामर्स को जो अवसर लागत को नहीं समझते हैं)। यदि वह सब कुछ जोड़ा गया था, तो अगला मानक C++होगा C++215xऔर संभवतः कंपाइलर डेवलपर्स द्वारा तीन सौ साल बाद पूरी तरह से लागू किया जाएगा।

वैसे भी, इस मामले पर मेरे (बल्कि बड़ा) विचार हैं। यदि गुणवत्ता के बजाय केवल वोटों को आधार पर सौंप दिया गया, तो मैं जल्द ही बाकी सभी को पानी से बाहर निकाल दूंगा। सुनने के लिए धन्यवाद :-)


2
FWIW, मुझे नहीं लगता कि C ++ निम्नानुसार है "एक ऑपरेशन करने के लिए केवल एक ही तरीका प्रदान करें" एक बाधा के रूप में। ठीक ही तो है, क्योंकि उदाहरण के लिए to_stringऔर लंबोदर दोनों चीजें उन चीजों के लिए उपयुक्त हैं जिन्हें आप पहले से कर सकते थे। मुझे लगता है कि एक "ऑपरेशन करने के लिए केवल एक ही तरीका" की व्याख्या कर सकते हैं " बहुत ही शिथिल रूप से उन दोनों को अनुमति देने के लिए, और एक ही समय में कार्यक्षमता के लगभग किसी भी दोहराव की अनुमति देने के लिए जिसे कोई भी कल्पना कर सकता है," अहा! नहीं! क्योंकि सुविधा बनाता है। यह ठीक-ठीक, लेकिन अधिक लंबी-घुमावदार विकल्प से एक समान रूप से अलग ऑपरेशन है! "। जो निश्चित रूप से लंबोदर का सच है।
स्टीव जेसोप

@ सच, ​​हां, यह मेरी ओर से बुरी तरह से कहा गया था। यह कहना अधिक सटीक है कि सभी समितियों के दिशानिर्देशों के बजाय प्रत्येक समिति के लिए दिशानिर्देश हैं। स्पष्ट करने के लिए समायोजित उत्तर
paxdiablo

2
बस एक बिंदु (कुछ में से): "कोई भी कोड बंदर दस मिनट में कोड़ा मार सकता है"। यकीन है, और अगर 100 कोड बंदरों (अच्छा अपमानजनक शब्द, BTW) करते हैं कि हर साल (शायद कम अनुमान), हमारे पास 1000 मिनट बर्बाद हो गए हैं। बहुत कुशल, क्या आपको नहीं लगता?
जर्गेन ए। इरहार्ड

1
@ Jürgen, यह अपमानजनक होने के लिए नहीं था (क्योंकि मैं वास्तव में किसी के लिए लेबल का वर्णन नहीं करता था), यह सिर्फ एक संकेत था कि powवास्तव में बहुत कौशल की आवश्यकता नहीं है। निश्चित रूप से मैं इसके बजाय मानक को कुछ प्रदान करना होगा जिसमें बहुत अधिक कौशल की आवश्यकता होगी, और यदि परिणाम को दोहराया जाना था तो बहुत अधिक समय बर्बाद होगा।
paxdiablo

2
@ eharo2, वर्तमान पाठ में "कोड बंदर" के साथ "आधा सभ्य कोडर" को बदलें। मुझे नहीं लगा कि यह अपमानजनक था, लेकिन मैंने सतर्क रहना सबसे अच्छा समझा और, ईमानदार होने के लिए, वर्तमान शब्द उसी विचार के पार जाता है।
पैक्सडीब्लो

41

किसी भी निश्चित-चौड़ाई के अभिन्न प्रकार के लिए, लगभग सभी संभावित इनपुट जोड़े प्रकार को ओवरफ्लो करते हैं, वैसे भी। किसी फ़ंक्शन को मानकीकृत करने का क्या उपयोग होता है जो अपने संभावित इनपुट के विशाल बहुमत के लिए उपयोगी परिणाम नहीं देता है?

फ़ंक्शन को उपयोगी बनाने के लिए आपको एक बड़े पूर्णांक प्रकार की आवश्यकता होती है, और अधिकांश बड़े पूर्णांक लाइब्रेरी फ़ंक्शन प्रदान करते हैं।


संपादित करें: सवाल पर एक टिप्पणी में, static_rtti लिखते हैं "अधिकांश इनपुट इसे अतिप्रवाह का कारण बनाते हैं; एक्सप और डबल पाउ के लिए भी यही सच है, मैं किसी को भी शिकायत करते नहीं देखता।" यह गलत है।

आइए exp, एक तरफ छोड़ दें , क्योंकि यह उस बिंदु के बगल में है (हालांकि यह वास्तव में मेरे मामले को मजबूत करेगा), और ध्यान केंद्रित करें double pow(double x, double y)। (X, y) जोड़े के किस भाग के लिए यह फ़ंक्शन कुछ उपयोगी करता है (यानी, केवल अतिप्रवाह या अंडरफ़्लो नहीं)?

मैं वास्तव में इनपुट जोड़े के केवल एक छोटे से हिस्से पर ध्यान केंद्रित करने जा रहा हूं, जिसके लिए powसमझ में आता है, क्योंकि यह मेरी बात को साबित करने के लिए पर्याप्त होगा: यदि x सकारात्मक है और y | <= 1, फिर powअतिप्रवाह या अंडरफ्लो नहीं होता है। इसमें सभी फ्लोटिंग-पॉइंट जोड़े के लगभग एक-चौथाई शामिल हैं (गैर-NaN फ्लोटिंग-पॉइंट संख्याओं का आधा हिस्सा सकारात्मक हैं, और गैर-NaN फ़्लोटिंग-पॉइंट संख्याओं के आधे से भी कम का परिमाण 1 से कम है)। जाहिर है, बहुत सारे अन्य इनपुट जोड़े हैं जिनके लिए powउपयोगी परिणाम उत्पन्न होते हैं, लेकिन हमने पता लगाया है कि यह सभी इनपुट का कम से कम एक-चौथाई है।

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

  • यदि प्रतिपादक 0 या 1 है, तो कोई भी आधार सार्थक है।
  • यदि घातांक 2 या अधिक है, तो 2 ^ (n / 2) से बड़ा कोई आधार सार्थक परिणाम नहीं देता है।

इस प्रकार, 2 ^ (2n) इनपुट जोड़े, 2 ^ (n + 1) + 2 ^ (3n / 2) से कम सार्थक परिणाम देते हैं। अगर हम देखें कि सबसे आम उपयोग की संभावना क्या है, तो 32-बिट पूर्णांक, इसका मतलब है कि इनपुट जोड़े के 1 प्रतिशत के 1/1000 वें क्रम पर कुछ बस अतिप्रवाह नहीं है।


8
वैसे भी यह सब मूक है। सिर्फ इसलिए कि एक फ़ंक्शन कुछ या बहुत सारे इनपुट के लिए मान्य नहीं है, यह इसे कम उपयोगी नहीं बनाता है।
स्थिर_पृथ्वी

2
@static_rtti: pow(x,y)किसी भी x के लिए शून्य से कम नहीं होगा अगर | y | <= 1. इनपुट का एक बहुत ही संकीर्ण बैंड है (बड़े x, y बहुत लगभग -1) जिसके लिए अंडरफ्लो होता है, लेकिन परिणाम अभी भी उस सीमा में सार्थक है।
स्टीफन कैनन

2
इसे और अधिक विचार देने के बाद, मैं अंडरफ्लो पर सहमत हूं। मुझे अभी भी लगता है कि यह सवाल के लिए प्रासंगिक नहीं है, हालांकि।
static_rtti

7
@ybungalobill: आपने इसे एक कारण के रूप में क्यों चुना? वैयक्तिकता, मैं बड़ी संख्या में समस्याओं और प्रोग्रामर के लिए उपयोगिता का पक्ष लूंगा, हार्पर अनुकूलित संस्करण बनाने की संभावना है जो कि भोले कार्यान्वयन की तुलना में तेज़ हैं जो कि अधिकांश प्रोग्रामर शायद लिखेंगे, और इसी तरह। आपकी कसौटी पूरी तरह से मनमाना लगती है, और, स्पष्ट रूप से, बिल्कुल व्यर्थ।
static_rtti

5
@StephenCanon: उज्ज्वल पक्ष पर, आपका तर्क दिखाता है कि पूर्णांक powका स्पष्ट रूप से सही-और-इष्टतम कार्यान्वयन केवल एक छोटी सी दिखने वाली तालिका है। :-)
आर .. गिटहब स्टॉप हेल्पिंग ICE

11

क्योंकि किसी भी रास्ते में सभी पूर्णांक शक्तियों का प्रतिनिधित्व करने का कोई तरीका नहीं है:

>>> print 2**-4
0.0625

3
एक छोटे आकार के संख्यात्मक प्रकार के लिए, अतिप्रवाह के कारण उस प्रकार के भीतर उस प्रकार की सभी शक्तियों का प्रतिनिधित्व करने का कोई तरीका नहीं है। लेकिन नकारात्मक शक्तियों के बारे में आपकी बात अधिक मान्य है।
क्रिस लुत्ज़

1
मैं नकारात्मक घातांक देखता हूं क्योंकि एक मानक कार्यान्वयन कुछ संभाल सकता है, या तो एक अनिर्दिष्ट int को घातांक के रूप में ले सकता है या शून्य को वापस कर सकता है जब एक नकारात्मक घातांक को इनपुट के रूप में साबित किया जाता है और एक int अपेक्षित आउटपुट होता है।
डैन ओ

3
या अलग हो गया है int pow(int base, unsigned int exponent)औरfloat pow(int base, int exponent)
Pankadoodle

4
वे एक नकारात्मक पूर्णांक पारित करने के लिए इसे अपरिभाषित व्यवहार के रूप में घोषित कर सकते थे।
जोहान्स शहाब -

2
सभी आधुनिक कार्यान्वयन पर, कुछ भी परे int pow(int base, unsigned char exponent)कुछ भी बेकार है। या तो आधार 0 है, या 1 है, और प्रतिपादक कोई फर्क नहीं पड़ता है, यह -1 है, जिसमें केवल प्रतिपादक मामलों का अंतिम बिट है, या अतिप्रवाह के दंड पर base >1 || base< -1किस मामले में exponent<256
मर्सल्ट्स

9

यह वास्तव में एक दिलचस्प सवाल है। एक तर्क जो मैंने चर्चा में नहीं पाया है वह तर्कों के लिए स्पष्ट वापसी मूल्यों की सरल कमी है। आइए गिनती करते हैं कि हाइपरथेटिक int pow_int(int, int)फ़ंक्शन विफल हो सकते हैं।

  1. बाढ़
  2. परिणाम अपरिभाषित pow_int(0,0)
  3. परिणाम का प्रतिनिधित्व नहीं किया जा सकता है pow_int(2,-1)

फ़ंक्शन में कम से कम 2 विफलता मोड हैं। इंटेगर इन मूल्यों का प्रतिनिधित्व नहीं कर सकते, इन मामलों में फ़ंक्शन के व्यवहार को मानक द्वारा परिभाषित करने की आवश्यकता होगी - और प्रोग्रामर को इस बात से अवगत होने की आवश्यकता होगी कि फ़ंक्शन इन मामलों को कैसे ठीक से हैंडल करता है।

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


लेकिन क्या पहले दो मामलों के powबीच एक फ़्लोट के लिए भी लागू नहीं होगा ? दो बड़ी फ़्लोट्स लें, एक को दूसरे की शक्ति तक बढ़ाएं और आपके पास एक ओवरफ़्लो हो। और pow(0.0, 0.0)अपने 2 बिंदु के रूप में एक ही समस्या का कारण होगा। पूर्णांक बनाम फ़्लोट्स के लिए पावर फ़ंक्शन को लागू करने के बीच आपका वास्तविक बिंदु एकमात्र वास्तविक अंतर है।
नंबर

7

संक्षिप्त जवाब:

pow(x, n)जहां nएक प्राकृतिक संख्या है वहां का एक विशेषज्ञता अक्सर समय प्रदर्शन के लिए उपयोगी है । लेकिन मानक पुस्तकालय की जेनेरिक pow()अभी भी बहुत अच्छी तरह से ( आश्चर्यजनक रूप से ) इस उद्देश्य के लिए काम करती है और यह मानक सी लाइब्रेरी में जितना संभव हो उतना कम शामिल करने के लिए बिल्कुल महत्वपूर्ण है ताकि इसे यथासंभव पोर्टेबल और आसान बनाया जा सके। दूसरी ओर, यह सी ++ मानक पुस्तकालय या एसटीएल में होने से बिल्कुल भी नहीं रोकता है, जो मुझे यकीन है कि कोई भी किसी तरह के एम्बेडेड प्लेटफॉर्म का उपयोग करने की योजना नहीं बना रहा है।

अब, लंबे उत्तर के लिए।

pow(x, n)nएक प्राकृतिक संख्या के लिए विशेषज्ञता द्वारा कई मामलों में बहुत तेजी से बनाया जा सकता है । मेरे द्वारा लिखे गए लगभग हर कार्यक्रम के लिए मुझे इस फ़ंक्शन के अपने कार्यान्वयन का उपयोग करना पड़ा है (लेकिन मैं सी में बहुत सारे गणितीय कार्यक्रम लिखता हूं)। विशेष ऑपरेशन O(log(n))समय में किया जा सकता है , लेकिन जब nछोटा होता है, तो एक सरल रैखिक संस्करण तेज हो सकता है। यहाँ दोनों के कार्यान्वयन हैं:


    // Computes x^n, where n is a natural number.
    double pown(double x, unsigned n)
    {
        double y = 1;
        // n = 2*d + r. x^n = (x^2)^d * x^r.
        unsigned d = n >> 1;
        unsigned r = n & 1;
        double x_2_d = d == 0? 1 : pown(x*x, d);
        double x_r = r == 0? 1 : x;
        return x_2_d*x_r;
    }
    // The linear implementation.
    double pown_l(double x, unsigned n)
    {
        double y = 1;
        for (unsigned i = 0; i < n; i++)
            y *= x;
        return y;
    }

(मैंने छोड़ दिया xऔर वापसी का मूल्य दोगुना हो गया क्योंकि इसका परिणाम pow(double x, unsigned n)एक डबल में फिट होगा जैसा कि अक्सर pow(double, double)होगा।)

(हाँ, pownपुनरावर्ती है, लेकिन स्टैक को तोड़ना बिल्कुल असंभव है क्योंकि अधिकतम स्टैक आकार लगभग बराबर होगा log_2(n)और nपूर्णांक है। यदि n64-बिट पूर्णांक है, जो आपको लगभग 64 के अधिकतम स्टैक आकार देता है। किसी भी हार्डवेयर में इतना चरम नहीं है स्मृति सीमाएं, केवल हार्डवेयर ढेर के साथ कुछ डोडी PIC को छोड़कर, जो केवल 3 से 8 फ़ंक्शन गहरी जाती हैं।)

प्रदर्शन के लिए, आपको आश्चर्य होगा कि बगीचे की विविधता pow(double, double)क्या सक्षम है। मैंने अपने 5-वर्षीय आईबीएम थिंकपैड xपर पुनरावृति संख्या के nबराबर और 10. के बराबर के साथ सौ मिलियन पुनरावृत्तियों का परीक्षण किया । इस परिदृश्य में, pown_lजीता। glibc pow()ने 12.0 उपयोगकर्ता सेकंड लिए, pown7.4 उपयोगकर्ता सेकंड लिए, और pown_lकेवल 6.5 उपयोगकर्ता सेकंड लिए। तो यह बहुत आश्चर्य की बात नहीं है। हम कमोबेश यही उम्मीद कर रहे थे।

फिर, मैंने xनिरंतर रहने दिया (मैंने इसे 2.5 पर सेट किया), और मैंने n0 से 19 सौ मिलियन बार लूप किया। इस बार, काफी अप्रत्याशित रूप से, glibc powजीता, और भूस्खलन से! इसमें केवल 2.0 उपयोगकर्ता सेकंड लगे। मेरे pown9.6 सेकंड लगे, और pown_l12.2 सेकंड लगे। यहाँ क्या हुआ? मैंने इसका पता लगाने के लिए एक और परीक्षण किया।

मैंने वही किया जो ऊपर से केवल xएक लाख के बराबर है। इस बार, pown9.6 में जीता। pown_l12.2 सेकंड और ग्लिबक पॉव ने 16.3 सेकेंड का समय लिया। अब, यह स्पष्ट है! glibc कम powहोने पर तीनों से बेहतर प्रदर्शन करता xहै, लेकिन जब xउच्च होता है तो सबसे खराब होता है। जब xउच्च होता है, pown_lतो nकम होने पर सबसे अच्छा प्रदर्शन करता है, और pownजब xउच्च होता है तो सबसे अच्छा प्रदर्शन करता है।

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

double pown_auto(double x, unsigned n, double x_expected, unsigned n_expected) {
    if (x_expected < x_threshold)
        return pow(x, n);
    if (n_expected < n_threshold)
        return pown_l(x, n);
    return pown(x, n);
}

जब तक x_expectedऔर n_expectedस्थिरांक को संकलित समय पर तय किया जाता है, संभवतः कुछ अन्य कैविट्स के साथ, इसके नमक के लायक एक अनुकूलन कंपाइलर पूरे pown_autoफ़ंक्शन कॉल को स्वचालित रूप से हटा देगा और इसे तीन एल्गोरिदम की उपयुक्त पसंद के साथ बदल देगा। (अब, यदि आप वास्तव में इसका उपयोग करने का प्रयास करने जा रहे हैं , तो आपको शायद इसके साथ थोड़ा खिलौना करना होगा, क्योंकि मैंने जो मैंने ऊपर लिखा है, उसे संकलित करने की कोशिश नहीं की थी ;)।

दूसरी ओर, glibc pow काम करता है और glibc पहले से ही काफी बड़ा है। सी मानक को पोर्टेबल माना जाता है, जिसमें विभिन्न एम्बेडेड डिवाइस शामिल हैं (वास्तव में एम्बेडेड डेवलपर्स हर जगह आम तौर पर सहमत होते हैं कि ग्लिब्क पहले से ही उनके लिए बहुत बड़ा है), और यह पोर्टेबल नहीं हो सकता है यदि प्रत्येक साधारण गणित फ़ंक्शन के लिए इसे हर शामिल करने की आवश्यकता है वैकल्पिक एल्गोरिथ्म जो उपयोग का हो सकता है। तो, यही कारण है कि यह सी मानक में नहीं है।

फुटनोट: समय प्रदर्शन के परीक्षण में, मैंने अपने कार्यों को अपेक्षाकृत उदार अनुकूलन झंडे ( -s -O2) दिए, जिनकी तुलना करने की संभावना है, अगर इससे भी बदतर नहीं है, तो मेरे सिस्टम (आर्च्लिनक्स) पर ग्लिबेक को संकलित करने की संभावना क्या थी, इसलिए परिणाम संभवतः हैं निष्पक्ष। अधिक कठोर परीक्षण के लिए, मुझे अपने आप को glibc संकलित करना होगा और मैं reeeally ऐसा करने का मन नहीं करता। मैं जेंटू का उपयोग करता था, इसलिए मुझे याद है कि कार्य स्वचालित होने पर भी कितना समय लगता है । परिणाम मेरे लिए पर्याप्त (या बल्कि अनिर्णायक) निर्णायक हैं। आप निश्चित रूप से यह स्वयं करने के लिए स्वागत करते हैं।

बोनस राउंड: एक पूर्णांक आउटपुट की आवश्यकता होने pow(x, n)पर सभी पूर्णांकों का एक विशेषज्ञता महत्वपूर्ण है, जो होता है। पी ^ एन तत्वों के साथ एन-आयामी सरणी के लिए मेमोरी आवंटित करने पर विचार करें। पी ^ एन बंद होने से भी संभवत: बेतरतीब ढंग से सेगफॉल्ट हो सकता है।


मुझे लगता है कि यदि आप पुनरावृत्ति से छुटकारा पा लेते हैं, तो आप स्टैक आवंटन के लिए आवश्यक समय बचाएंगे। और हाँ, हमारे पास एक ऐसी स्थिति थी जहाँ पाउ सब कुछ धीमा कर रहा था और हमें अपना स्वयं का पॉव लागू करना था।
सांबतियॉन

"किसी के पास ऐसी चरम स्मृति सीमाएं नहीं हैं" झूठी है। PIC में अक्सर 8 के लिए अधिकतम 3 (उदाहरण PIC10F200) के लिए एक सीमित कॉल स्टैक होता है (उदाहरण 16F722A है) कॉल (PIC फ़ंक्शन फ़ंक्शन के लिए एक हार्डवेयर स्टैक का उपयोग करते हैं)।
12431234123412341234123

ओह, यार वह क्रूर लोल। ठीक है, इसलिए यह उन PIC पर काम नहीं करेगा।
enigmaticPhysicist

पूर्णांक आधार के साथ-साथ शक्ति के लिए, जैसे प्रश्न के बारे में पूछ रहा है, संकलक (जीसीसी और क्लैंग) आसानी से पुनरावृत्त (पुनरावर्ती के बजाय) कार्यान्वयन से एक शाखाहीन लूप का उत्पादन करेगा। यह शाखा को प्रत्येक बिट से गलतफहमी से बचाती है ngodbolt.org/z/L9Kb98 । gcc और clang आपकी पुनरावर्ती परिभाषा को एक साधारण लूप में अनुकूलित करने में विफल होते हैं, और वास्तव में प्रत्येक बिट पर शाखा करते हैं n। ( pown_iter(double,unsigned)वे अभी भी शाखा के लिए, लेकिन एक शाखा रहित SSE2 या SSE4.1 कार्यान्वयन x86 asm में या C आंतरिक के साथ संभव होना चाहिए। लेकिन यहां तक ​​कि पुनरावृत्ति से बेहतर है)
पीटर कॉर्डेस

बकवास, अब मुझे यह सुनिश्चित करने के लिए कि लूप-आधारित संस्करण के साथ फिर से बेंचमार्क करना है। मैं इसके बारे में सोचूंगा।
enigmaticPhysicist

6

C ++ का अतिरिक्त अधिभार नहीं होने का एक कारण C के साथ संगत होना है।

C ++ 98 में फ़ंक्शंस होते हैं double pow(double, int), लेकिन इन्हें C ++ 11 में इस तर्क के साथ हटा दिया गया है कि C99 में इन्हें शामिल नहीं किया गया था।

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3286.html#550

थोड़ा और सटीक परिणाम प्राप्त करने का अर्थ है थोड़ा अलग परिणाम प्राप्त करना।


3

विश्व लगातार विकसित हो रहा है और इसलिए प्रोग्रामिंग भाषाएँ हैं। C दशमलव TR का चौथा भाग कुछ और कार्यों को जोड़ता है <math.h>। इस कार्य के लिए इन कार्यों के दो परिवार रुचि ले सकते हैं:

  • pownकाम करता है, कि एक चल बिन्दु संख्या और एक लेता है intmax_tप्रतिपादक।
  • powrकाम करता है, कि दो अस्थायी अंक संख्या (लेता है xऔर y) और गणना xसत्ता में yफार्मूले के साथ exp(y*log(x))

ऐसा लगता है कि मानक लोगों ने अंततः इन सुविधाओं को मानक पुस्तकालय में एकीकृत करने के लिए पर्याप्त उपयोगी माना। हालांकि, तर्कसंगत यह है कि इन कार्यों की सिफारिश आईएसओ / आईईसी / आईईईई 60559: 2011 बाइनरी और दशमलव फ्लोटिंग नंबर के लिए मानक है। मैं यह सुनिश्चित करने के लिए नहीं कह सकता हूं कि C89 के समय "मानक" का पालन किया गया था, लेकिन भविष्य के प्रस्तावों का <math.h>संभवतः आईएसओ / IEC / IEEE 60559 मानक के भविष्य के प्रस्तावों से बहुत अधिक प्रभावित होगा ।

ध्यान दें कि दशमलव TR का चौथा भाग C2x (अगले प्रमुख C संशोधन) में शामिल नहीं किया जाएगा, और संभवतः बाद में एक वैकल्पिक सुविधा के रूप में शामिल किया जाएगा। ऐसा कोई इरादा नहीं है जिसे मैं टीआर के इस हिस्से को भविष्य के सी ++ संशोधन में शामिल करना जानता हूं।


¹ आप कुछ काम में प्रगति दस्तावेज़ीकरण देख सकते हैं यहां


क्या कोई प्रशंसनीय क्रियान्वयन है जिसमें pownएक घातांक से अधिक का उपयोग करने से LONG_MAXकभी मूल्य का उपयोग करने से अलग होना चाहिए LONG_MAX, या जहां से कम LONG_MINमूल्य से अलग मूल्य का उत्पादन करना चाहिए LONG_MIN? मुझे आश्चर्य है कि intmax_tप्रतिपादक के लिए उपयोग करने से क्या लाभ प्राप्त होता है ?
सुपरकाट

@supercat कोई विचार नहीं, क्षमा करें।
मोरवेन सेप

यह उल्लेख करने के लिए सार्थक हो सकता है कि, मानक को देखते हुए, यह एक वैकल्पिक "crpown" फ़ंक्शन को भी परिभाषित करता है, जो कि यदि परिभाषित किया गया है, तो "पोज" का सही ढंग से गोल संस्करण हो सकता है; मानक अन्यथा सटीकता की आवश्यक डिग्री निर्दिष्ट नहीं करता है। एक तेज़ और मध्यम-सटीक "पोज़" को लागू करना आसान है, लेकिन सभी मामलों में सही गोलाई सुनिश्चित करना बहुत अधिक महंगा है।
सुपरकाट

2

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

(एक बात के लिए, लघुगणक शक्तियों को गुणन में कम करते हैं, लेकिन पूर्णांकों के लघुगणक अधिकांश इनपुट के लिए बहुत सटीकता खो देते हैं)

स्टीफन सही है कि आधुनिक प्रोसेसर पर यह अब सच नहीं है, लेकिन सी मानक जब गणित कार्यों का चयन किया गया था (सी ++ ने केवल सी फ़ंक्शन का इस्तेमाल किया) अब क्या है, 20 साल पुराना है?


5
मैं किसी भी मौजूदा वास्तुकला के लिए एक FPU अनुदेश के साथ पता नहीं है pow। x86 में एक y log2 xनिर्देश ( fyl2x) है जिसे किसी powफ़ंक्शन के पहले भाग के रूप में उपयोग किया जा सकता है , लेकिन एक powफ़ंक्शन जिस तरह से लिखा जाता है वह वर्तमान हार्डवेयर पर निष्पादित करने के लिए सैकड़ों चक्र लेता है; एक अच्छी तरह से लिखा पूर्णांक घातांक दिनचर्या कई गुना तेज है।
स्टीफन कैनन

मुझे नहीं पता कि "सैकड़ों" सटीक है, fyl2x के लिए लगभग 150 चक्र लगता है, फिर अधिकांश आधुनिक सीपीयू पर f2xm1 और जो अन्य निर्देशों के साथ पाइपलाइज़ हो जाता है। लेकिन आप सही हैं कि एक अच्छी तरह से पूर्ण पूर्णांक कार्यान्वयन (इन दिनों) तेजी से होना चाहिए क्योंकि IMUL को फ़्लोटिंग-पॉइंट निर्देशों की तुलना में बहुत अधिक खर्च किया गया है। वापस जब C मानक लिखा गया था, हालांकि, IMUL काफी महंगा था और एक लूप में इसका उपयोग संभवतः FPU का उपयोग करने से अधिक समय लेता था।
बेन वोइगट

2
सुधार के मद्देनजर मेरे वोट को बदल दिया; फिर भी, (ए) ध्यान रखें कि सी मानक 1999 में एक प्रमुख संशोधन (गणित पुस्तकालय के एक बड़े विस्तार सहित) से गुजरा, और (बी) कि सी मानक किसी भी विशिष्ट प्रोसेसर वास्तुकला के लिए नहीं लिखा है - उपस्थिति या x86 पर FPU निर्देशों की अनुपस्थिति अनिवार्य रूप से कुछ भी नहीं है जो C समिति मानकीकृत करने के लिए काम करती है।
स्टीफन कैनन

यह किसी भी वास्तुकला से जुड़ा नहीं है, सच है, लेकिन पूर्णांक की तुलना में एक लुकअप टेबल इंटरपोलेशन (आमतौर पर फ्लोटिंग पॉइंट कार्यान्वयन के लिए इस्तेमाल किया गया) की सापेक्ष लागत सभी आर्किटेक्चर के लिए बहुत समान रूप से बदल गई है जो मुझे लगता है।
बेन वोइगट

1

यहाँ वास्तव में सरल O (लॉग (n)) pow () का कार्यान्वयन है जो पूर्णांक सहित किसी भी संख्यात्मक प्रकार के लिए काम करता है :

template<typename T>
static constexpr inline T pown(T x, unsigned p) {
    T result = 1;

    while (p) {
        if (p & 0x1) {
            result *= x;
        }
        x *= x;
        p >>= 1;
    }

    return result;
}

यह enigmaticPhysicist के O (लॉग (n)) कार्यान्वयन से बेहतर है क्योंकि यह पुनरावृत्ति का उपयोग नहीं करता है।

यह भी लगभग हमेशा उनके रैखिक कार्यान्वयन की तुलना में तेज़ है (जब तक p> ~ 3) क्योंकि:

  • इसके लिए किसी अतिरिक्त मेमोरी की आवश्यकता नहीं है
  • यह केवल पाश प्रति 1.5x अधिक संचालन करता है
  • यह केवल ~ 1.25x अधिक मेमोरी अपडेट प्रति लूप करता है

-2

तथ्य की बात के रूप में, यह करता है।

C ++ 11 के बाद से pow(int, int)--- और इससे भी अधिक सामान्य मामलों का एक कार्यान्वित कार्यान्वयन है , http://en.cppreference.com/w/cpp/numeric/math/pow में देखें (7)


संपादित करें: शुद्धतावादियों का तर्क है कि यह सही नहीं है, क्योंकि वास्तव में "प्रमोटेड" टाइपिंग का उपयोग किया जाता है। एक तरह से या किसी अन्य, एक को एक सही intपरिणाम मिलता है, या एक त्रुटि, intमापदंडों पर ।


2
यह गलत है। (7) अधिभार वह pow ( Arithmetic1 base, Arithmetic2 exp )होता है, जिसे आपने पढ़ा होगा doubleया long doubleयदि आप विवरण पढ़ चुके हैं: "7) अंकगणित प्रकार के तर्कों के सभी संयोजनों के लिए अधिभार या फ़ंक्शन टेम्पलेट का एक सेट 1-3 द्वारा कवर नहीं किया गया है। यदि कोई तर्क है। अभिन्न प्रकार है, इसे डबल करने के लिए कास्ट किया जाता है। यदि कोई तर्क लंबा डबल है, तो रिटर्न टाइप प्रोमोटेड भी लंबा डबल है, अन्यथा रिटर्न टाइप हमेशा डबल होता है। "
फुलकव

यहाँ क्या गलत है? मैंने केवल इतना कहा कि आजकल (C ++ 11 के बाद से) एक टेम्प्लेटेड पाव ( , ) मानक पुस्तकालय में है, जो कि 2010 में नहीं था।
दिमा पासेनिक

5
नहीं, यह नहीं है। टेंपलेट्स इन प्रकारों को डबल या लॉन्ग डबल तक बढ़ावा देते हैं। तो यह नीचे के डबल्स पर काम करता है।
Trismegistos

1
@Trismegistos यह अभी भी इंट मापदंडों की अनुमति देता है। यदि यह टेम्प्लेट नहीं था, तो अंतर मापदंडों को पारित करने से यह एक फ्लोट के रूप में बिट में व्याख्या करने का कारण बनता है, जिससे मनमाने ढंग से अप्रत्याशित परिणाम हो सकते हैं। मिश्रित इनपुट मूल्यों के साथ भी ऐसा ही होता है। उदा pow(1.5f, 3)= 1072693280लेकिन pow(1.5f, float(3))=3.375
मार्क जेरोनिमस

2
ओपी ने पूछा int pow(int, int), लेकिन सी ++ 11 केवल प्रदान करता है double pow(int, int)। @Phuclv की व्याख्या देखें।
xuhdev

-4

एक बहुत ही सरल कारण:

5^-2 = 1/25

एसटीएल पुस्तकालय में सब कुछ सबसे सटीक, मजबूत सामान कल्पना पर आधारित है। निश्चित रूप से, इंट एक शून्य (1/25 से) पर वापस आ जाएगा, लेकिन यह एक गलत उत्तर होगा।

मैं मानता हूं, यह कुछ मामलों में अजीब है।


3
एक अहस्ताक्षरित दूसरे तर्क की आवश्यकता स्पष्ट रूप से आवश्यक है। ऐसे कई अनुप्रयोग हैं जिनके लिए केवल गैर-नकारात्मक पूर्णांक शक्तियों की आवश्यकता होती है।
enigmaticPhysicist
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.