.NET फ्रेमवर्क में Math.Pow () कैसे लागू किया जाता है?


432

मैं एक बी ( गणना a = 2और b = 50) की गणना के लिए एक कुशल दृष्टिकोण की तलाश कर रहा था । चीजों को शुरू करने के लिए, मैंने Math.Pow()फ़ंक्शन के कार्यान्वयन पर एक नज़र डालने का फैसला किया । लेकिन .NET रिफ्लेक्टर में , मैंने पाया कि यह था:

[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical]
public static extern double Pow(double x, double y);

ऐसे कौन से संसाधन हैं जिनमें मैं देख सकता हूं कि जब मैं Math.Pow()फ़ंक्शन को कॉल करता हूं तो क्या हो रहा है?


15
एक FYI के रूप में, यदि आप InternalCallएक externसंशोधक के साथ पूरे के बारे में भ्रमित हैं (जैसा कि वे परस्पर विरोधी प्रतीत होते हैं), तो कृपया प्रश्न (और परिणामी उत्तर) देखें जो मैंने इस एक ही चीज़ के बारे में पोस्ट किया है।
क्रेगटीपी

6
एक 2^xऑपरेशन के लिए यदि xपूर्णांक है तो परिणाम एक पारी ऑपरेशन है। तो शायद आप के एक mantissa 2और एक घातांक का उपयोग करके परिणाम का निर्माण कर सकते हैं x
ja72

@SurajJain आपकी टिप्पणी वास्तव में एक सवाल है जिसे आपको अलग से पोस्ट करने की आवश्यकता है।
ja72

@ सुरजजैन मैं आपसे सहमत हूँ। मैं एक मॉडरेटर नहीं हूं इसलिए मैं यहां बहुत कुछ नहीं कर सकता। शायद downvote सवाल meta.stackoverflow.com
ja72

जवाबों:


854

MethodImplOptions.InternalCall

इसका मतलब है कि विधि वास्तव में सीएलआर में लागू की गई है, सी ++ में लिखा गया है। बस-इन-टाइम कंपाइलर आंतरिक रूप से कार्यान्वित विधियों के साथ एक तालिका को सुरक्षित करता है और सीधे C ++ फ़ंक्शन को कॉल संकलित करता है।

कोड पर एक नज़र रखने के लिए CLR के लिए स्रोत कोड की आवश्यकता होती है। आप SSCLI20 वितरण से प्राप्त कर सकते हैं । यह .NET 2.0 समय सीमा के आसपास लिखा गया था, मैंने निम्न-स्तरीय कार्यान्वयन पाया है, जैसे Math.Pow()CLR के बाद के संस्करणों के लिए अभी भी काफी हद तक सटीक है।

लुकअप तालिका clr / src / vm / ecall.cpp में स्थित है। वह अनुभाग जो Math.Pow()इस प्रकार दिखता है:

FCFuncStart(gMathFuncs)
    FCIntrinsic("Sin", COMDouble::Sin, CORINFO_INTRINSIC_Sin)
    FCIntrinsic("Cos", COMDouble::Cos, CORINFO_INTRINSIC_Cos)
    FCIntrinsic("Sqrt", COMDouble::Sqrt, CORINFO_INTRINSIC_Sqrt)
    FCIntrinsic("Round", COMDouble::Round, CORINFO_INTRINSIC_Round)
    FCIntrinsicSig("Abs", &gsig_SM_Flt_RetFlt, COMDouble::AbsFlt, CORINFO_INTRINSIC_Abs)
    FCIntrinsicSig("Abs", &gsig_SM_Dbl_RetDbl, COMDouble::AbsDbl, CORINFO_INTRINSIC_Abs)
    FCFuncElement("Exp", COMDouble::Exp)
    FCFuncElement("Pow", COMDouble::Pow)
    // etc..
FCFuncEnd()

"COMDouble" की खोज आपको clr / src / classlibnative / float / comfloat.cpp पर ले जाती है। मैं आपको कोड छोड़ दूँगा, बस अपने लिए एक नज़र रखना होगा। यह मूल रूप से कोने के मामलों की जाँच करता है, फिर CRT के संस्करण को कॉल करता है pow()

केवल अन्य कार्यान्वयन विवरण जो दिलचस्प है, तालिका में FCIntrinsic मैक्रो है। यह संकेत है कि घबराना एक आंतरिक के रूप में कार्य को लागू कर सकता है। दूसरे शब्दों में, फ्लोटिंग पॉइंट मशीन कोड इंस्ट्रक्शन के साथ फंक्शन कॉल को स्थानापन्न करें। जो इसके लिए नहीं है Pow(), इसके लिए कोई एफपीयू निर्देश नहीं है। लेकिन निश्चित रूप से अन्य सरल संचालन के लिए। उल्लेखनीय है कि यह C ++ में समान कोड की तुलना में C # में फ्लोटिंग पॉइंट गणित को काफी तेज बना सकता है, इस कारण की वजह से इस उत्तर को जांचें ।

वैसे, यदि आप Visual Studio vc / crt / src निर्देशिका का पूर्ण संस्करण है, तो CRT के लिए स्रोत कोड भी उपलब्ध है। आप दीवार पर हिट करेंगे pow(), हालांकि, Microsoft ने इंटेल से वह कोड खरीदा था। इंटेल इंजीनियरों की तुलना में बेहतर काम करने की संभावना नहीं है। हालाँकि मेरी हाई-स्कूल किताब की पहचान दो बार तेज़ थी जब मैंने इसे आज़माया:

public static double FasterPow(double x, double y) {
    return Math.Exp(y * Math.Log(x));
}

लेकिन एक सही विकल्प नहीं है क्योंकि यह 3 फ्लोटिंग पॉइंट ऑपरेशंस से एरर जमा करता है और पॉवो () के अजीबोगरीब डोमेन समस्याओं से नहीं निपटता है। जैसे 0 ^ 0 और -इन्फिनिटी किसी भी शक्ति के लिए उठाया।


437
महान जवाब, स्टैकओवरफ़्लो को इस तरह की चीज़ की ज़रूरत है, इसके बजाय 'आप ऐसा क्यों जानना चाहेंगे?' बहुत बार ऐसा होता है।
टॉम डब्ल्यू

16
@ मुझे बताओ - मुझे नहीं पता, इंटेल इंजीनियरों का मजाक बनाने से छोटा है। मेरी हाई स्कूल की किताब में एक नकारात्मक अभिन्न की शक्ति के लिए कुछ उठाने की समस्या है। पॉव (x, -2) पूरी तरह से संगणक है, पॉव (x, -2.1) अपरिभाषित है। डोमेन समस्याओं से निपटने के लिए एक कुतिया हैं।
हंस पसंत

12
@ BlueRaja-DannyPflughoeft: फ्लोटिंग-पॉइंट ऑपरेशन्स सही-सही मूल्य के लिए जितना संभव हो सके, यह सुनिश्चित करने के लिए बहुत प्रयास किया जाता है। powसटीक रूप से लागू करने के लिए कुख्यात मुश्किल है, एक ट्रान्सेंडैंटल फ़ंक्शन ( टेबल-मेकर की दुविधा ) देखें। यह एक अभिन्न शक्ति के साथ बहुत आसान है।
पोर्स

9
@ हंस पासेंट: क्यों होगा पी.वी. (x, -2.1) अपरिभाषित? गणितीय रूप से pow को सभी x और y के लिए हर जगह परिभाषित किया गया है। आप नकारात्मक x और गैर पूर्णांक y के लिए जटिल संख्या प्राप्त करते हैं।
जूल्स

8
@ जूल्स पॉव (0, 0) परिभाषित नहीं है।
नक्काशी

110

हंस पसंत का जवाब बहुत अच्छा है, लेकिन मैं यह जोड़ना चाहूंगा कि यदि bपूर्णांक है, तो a^bबाइनरी अपघटन के साथ बहुत कुशलता से गणना की जा सकती है। यहाँ हेनरी वॉरेन हैकर डिलाइट से एक संशोधित संस्करण है :

public static int iexp(int a, uint b) {
    int y = 1;

    while(true) {
        if ((b & 1) != 0) y = a*y;
        b = b >> 1;
        if (b == 0) return y;
        a *= a;
    }    
}

वह ध्यान देता है कि यह ऑपरेशन सभी बी के लिए इष्टतम है (अंकगणित या तार्किक संचालन की न्यूनतम संख्या) <15. a^b , किसी भी व्यापक बी के अलावा किसी अन्य बी के लिए खोज। यह एक एनपी-हार्ड समस्या है। तो मूल रूप से इसका मतलब है कि द्विआधारी अपघटन उतना ही अच्छा है जितना इसे मिलता है।


11
यह एल्गोरिथ्म ( वर्ग और गुणा ) aएक अस्थायी बिंदु संख्या होने पर भी लागू होता है।
कोडइन्चोस

14
व्यवहार में यह देशी वर्ग की तुलना में काफी बेहतर और कई गुना बेहतर है। उदाहरण के लिए छोटे घातांक के लिए लुकअप टेबल तैयार करना ताकि आप कई बार वर्ग कर सकें और उसके बाद ही तय किए गए घातांक के लिए अनुकूलित वर्ग-अतिरिक्त श्रृंखलाओं का निर्माण या गुणा कर सकें। इस तरह की समस्या महत्वपूर्ण क्रिप्टोग्राफिक एल्गोरिदम का अभिन्न अंग है, इसलिए इसे अनुकूलित करने पर काफी काम किया गया है। एनपी कठोरता केवल सबसे खराब मामला असममितता है, हम अक्सर अभ्यास में उत्पन्न होने वाली समस्याओं के उदाहरणों के लिए इष्टतम या निकट-आशावादी समाधान का उत्पादन कर सकते हैं।
कोडइन्चोस

पाठ में aपूर्णांक होने का उल्लेख नहीं है , लेकिन कोड करता है। उसी के परिणामस्वरूप, मैं पाठ की "बहुत ही कुशल" गणना के परिणाम की सटीकता के बारे में आश्चर्य करता हूं ।
एंड्रयू मॉर्टन

69

यदि स्वतंत्र रूप से उपलब्ध सी संस्करणpow किसी भी संकेत है, तो यह वैसा नहीं दिखता जैसा आप अपेक्षा करते हैं। .NET संस्करण को खोजने के लिए यह आपके लिए ज्यादा मददगार नहीं होगा, क्योंकि जो समस्या आप हल कर रहे हैं (यानी पूर्णांक वाला) सरलता के परिमाण के आदेश हैं, और घातांक के साथ C # कोड की कुछ पंक्तियों में हल किया जा सकता है कलन विधि द्वारा


आपके उत्तर के लिए धन्यवाद। पहले लिंक ने मुझे आश्चर्यचकित कर दिया क्योंकि मैं इस तरह के बड़े पैमाने पर तकनीकी कार्यान्वयन की उम्मीद नहीं कर रहा था। हालांकि हंस पसेंट का उत्तर पुष्टि करता है कि इसकी .Net दुनिया में भी यही है। मुझे लगता है कि मैं स्क्वेयर एल्गोरिथ्म लिंक में सूचीबद्ध कुछ तकनीकों का उपयोग करके समस्या को हल कर सकता हूं। एक बार फिर धन्यवाद।
पवन मिश्रा

2
मुझे विश्वास नहीं है कि यह कोड कुशल है। 30 स्थानीय चर बस सभी रजिस्टरों को टक्कर देना चाहिए। मुझे लगता है कि यह केवल एआरएम संस्करण है, लेकिन x86 में 30 स्थानीय चर भयानक हैं।
एलेक्स झूकोव्स्की
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.