2013-02-04 42 views
5

मेरे पास एक संख्यात्मक कोड है जो एक समीकरण f(x) = 0 हल करता है, जिसमें मुझे x को p पर x उठाना है। मैं चीजों का एक समूह का उपयोग करके इसे हल करता हूं, लेकिन अंत में मेरे पास न्यूटन की विधि है। समाधान x = 1 के बराबर होता है, और इस प्रकार मेरी समस्याओं का कारण है। जब पुनरावृत्त समाधान 1 के करीब आता है, तो x = 1 + 1e-13 कहें, std::pow(x, p) की गणना करने के लिए आवश्यक समय 100 के कारक द्वारा आसानी से बढ़ता है, जिससे मेरा कोड अनुपयोगी हो जाता है।बहुत धीमी std :: pow() बेस के लिए बहुत करीब 1

इस बात को चलाने वाली मशीन CentOS पर AMD64 (Opteron 6172) है, और कमांड है। इसी तरह का व्यवहार मेरी सभी मशीनों, सभी x64 पर दिखाई देता है। दस्तावेज here के रूप में, यह केवल मेरी समस्या नहीं है (यानी, कोई और भी pissed है), केवल x64 पर दिखाई देता है और केवल 1.0 के करीब दिखाई देता है। इसी तरह की चीज exp होती है।

इस समस्या को हल करना मेरे लिए महत्वपूर्ण है। क्या किसी को पता है कि इस धीमेपन के आसपास जाने का कोई तरीका है?

संपादित करें: जॉन ने इंगित किया कि यह denormals के कारण है। सवाल यह है कि, इसे कैसे ठीक किया जाए? कोड GNU Octave के भीतर उपयोग के लिए g++ के साथ संकलित C++ है। ऐसा प्रतीत होता है कि, हालांकि मैंने CXXFLAGS को -mtune=native और -ffast-math शामिल करने के लिए सेट किया है, जो मदद नहीं कर रहा है और कोड धीरे-धीरे चलता है।

अब के लिए PSEUDO- समाधान: इस समस्या की परवाह करने वाले सभी लोगों के लिए, नीचे दिए गए समाधान व्यक्तिगत रूप से मेरे लिए काम नहीं करते थे। मुझे वास्तव में std::pow() की सामान्य गति की आवश्यकता है, लेकिन x = 1 के आसपास आलसीता के बिना। मेरे लिए व्यक्तिगत रूप से समाधान निम्नलिखित हैक उपयोग करने के लिए है:

inline double mpow(double x, double p) __attribute__ ((const)); 

inline double mpow(double x, double p) 
{ 
    double y(x - 1.0); 
    return (std::abs(y) > 1e-4) ? (std::pow(x, p)) : (1.0 + p * y * (1.0 + (p - 1.0) * y * (0.5 + (1.0/6.0) * (p - 2.0) * y))); 
} 

बाध्य बदला जा सकता है, लेकिन -40 < पी < 40 के लिए त्रुटि 1e-11 के बारे में है, जो काफी अच्छा है से छोटा है। ओवरहेड जो मैंने पाया उससे कम है, इस प्रकार यह मेरे लिए मुद्दा हल करता है।

+5

यह [सामान्य से कम संख्या] के साथ सामान्य प्रदर्शन की समस्याओं से संबंधित हो सकता (http://en.wikipedia.org/wiki/Denormal_number)। फ्लोटिंग पॉइंट मानों के साथ कंप्यूटेशंस 0 के बहुत करीब सामान्य से 100x धीमी हो सकती हैं। Http://stackoverflow.com/questions/9314534/why-does-changing-0-1f-to-0-slow-down-performance-by-10x देखें। –

+0

अच्छा बिंदु। इस समाधान को हल करने के लिए कोई सुझाव? अगर वे काफी करीब हैं तो संख्याओं को ठीक से ठीक करें? –

+0

@ जॉन कुगेलमैन: यदि आप लिंक पढ़ते हैं, तो ऐसा इसलिए होता है क्योंकि ग्लिबैक कुछ धीमे फ़ंक्शन का उपयोग करता है (नाम '__slowpow') जब कुछ इनपुट मान दिए जाते हैं। – interjay

उत्तर

0

यह भी आपका एल्गोरिदम हो सकता है। शायद न्यूटन की विधि के बजाय बीएफजीएस जैसे कुछ पर स्विच करने में मदद मिलेगी।

आप अपने अभिसरण मानदंडों के बारे में कुछ भी नहीं कहते हैं। शायद उनको भी समायोजन की जरूरत है।

+0

वह 'पाउ' लागू नहीं कर रहा है, लेकिन मानक पुस्तकालय कार्यान्वयन का उपयोग कर रहा है। :) – jalf

+1

नहीं, यह वास्तव में वास्तव में मुद्दा है। मैंने कोड का समय दिया है और जब तक मैंने कारण को कम नहीं किया तब तक सब कुछ करने की कोशिश की। –

+0

मुझे यह मिल गया। बीएफजीएस को मैट्रिक्स बनाने के तरीके के साथ करना है, जरूरी नहीं कि पावर गणना। – duffymo

9

स्पष्ट कार्यप्रणाली यह है कि वास्तविकताओं में, a ** b == exp(log(a) * b) और इसके बजाय उस फ़ॉर्म का उपयोग करें। आपको यह जांचना होगा कि यह आपके परिणामों की सटीकता को प्रतिकूल रूप से प्रभावित नहीं करता है। संपादित करें: जैसा कि चर्चा की गई है, यह भी मंदी से लगभग एक डिग्री तक पीड़ित है।

समस्या कम से कम नहीं, denormals नहीं है; exp(-2.4980018054066093e-15) की गणना करने की कोशिश करने से भी वही मंदी होती है, और -2.4 9 8380540660 9 3 -15 निश्चित रूप से असामान्य नहीं है।

आप अपने परिणामों की सटीकता के बारे में परवाह नहीं करते हैं, तो या तो exponend या प्रतिपादक धीमी गति से क्षेत्र के बाहर आप मिलना चाहिए स्केलिंग:

sqrt(pow(a, b * 2)) 
pow(a * 2, b)/pow(2, b) 
... 

इस बग glibc देखरेख करने के लिए जाना जाता है: http://sourceware.org/bugzilla/show_bug.cgi?id=13932 - यदि आप एक समाधान के विरोध में एक फिक्स की तलाश में हैं तो आप ओपन सोर्स अनुभव के साथ एक फ्लोटिंग पॉइंट गणित विशेषज्ञ को कम करना चाहते हैं।

+0

यह एक पाउ() से लगभग 4x तेज है, कोशिश की। –

+0

स्केलिंग 'x' या' p' ने मेरे परीक्षणों में मदद नहीं की। ग्लिब में समस्या को ठीक करने में मदद नहीं मिलेगी, क्योंकि इस चीज़ को मैक ओएस और MATLAB पर चलाना है, जो इसकी एमएक्स फाइलों को संकलित करने के लिए एक प्राचीन जीसीसी का उपयोग करता है। –

1

64-बिट लिनक्स?

उपयोग पॉव() FreeBSD से कोड।

लिनक्स सी पुस्तकालय (glibc) कुछ इनपुट के लिए भयानक बुरी से बुरी हालत प्रदर्शन है।

देखें: http://entropymine.com/imageworsener/slowpow/