मैंने कुछ समय पहले एक कोड लिखा था जिसमें पुस्तकालय कार्यों का उपयोग किए बिना गणना करने का प्रयास किया गया था । कल, मैं पुराने कोड की समीक्षा कर रहा था, और मैंने इसे जितनी जल्दी हो सके बनाने की कोशिश की, (और सही)। यहाँ मेरा अब तक का प्रयास है:
const double ee = exp(1);
double series_ln_taylor(double n){ /* n = e^a * b, where a is an non-negative integer */
double lgVal = 0, term, now;
int i, flag = 1;
if ( n <= 0 ) return 1e-300;
if ( n * ee < 1 )
n = 1.0 / n, flag = -1; /* for extremely small n, use e^-x = 1/n */
for ( term = 1; term < n ; term *= ee, lgVal++ );
n /= term;
/* log(1 - x) = -x - x**2/2 - x**3/3... */
n = 1 - n;
now = term = n;
for ( i = 1 ; ; ){
lgVal -= now;
term *= n;
now = term / ++i;
if ( now < 1e-17 ) break;
}
if ( flag == -1 ) lgVal = -lgVal;
return lgVal;
}
यहाँ मैं ऐसा खोजने की कोशिश कर रहा हूँ कि e a अभी n पर है, और फिर मैं n का लघुगणक मान जोड़ता हूँ , जो 1. से कम है। इस बिंदु पर,log(1-x)के टेलर विस्तार काउपयोग बिना किसी चिंता के किया जा सकता है।
मैंने हाल ही में संख्यात्मक विश्लेषण में रुचि पैदा की है, और इसीलिए मैं यह सवाल पूछने में मदद नहीं कर सकता कि यह कोड सेगमेंट कितनी तेजी से चल सकता है, जबकि यह काफी सही है? क्या मुझे कुछ अन्य तरीकों पर स्विच करने की आवश्यकता है, उदाहरण के लिए, इस तरह से जारी अंश का उपयोग करना ?
सी मानक पुस्तकालय के साथ प्रदान की समारोह लगभग 5.1 गुना इस कार्यान्वयन की तुलना में तेजी है।
अद्यतन 1 : विकिपीडिया में उल्लिखित हाइपरबोलिक आर्कटिक श्रृंखला का उपयोग करते हुए , गणना सी मानक पुस्तकालय लॉग फ़ंक्शन की तुलना में लगभग 2.2 गुना धीमी लगती है। हालाँकि, मैंने बड़े पैमाने पर प्रदर्शन की जाँच नहीं की है, और बड़ी संख्या के लिए, मेरा वर्तमान कार्यान्वयन वास्तव में धीमा प्रतीत होता है। यदि मैं प्रबंधित कर सकता हूं तो मैं अपने दोनों कार्यान्वयन को चेक बाउंड की संख्या के लिए त्रुटि बाउंड और औसत समय के लिए जाँचना चाहता हूँ। यहाँ मेरा दूसरा प्रयास है।
double series_ln_arctanh(double n){ /* n = e^a * b, where a is an non-negative integer */
double lgVal = 0, term, now, sm;
int i, flag = 1;
if ( n <= 0 ) return 1e-300;
if ( n * ee < 1 ) n = 1.0 / n, flag = -1; /* for extremely small n, use e^-x = 1/n */
for ( term = 1; term < n ; term *= ee, lgVal++ );
n /= term;
/* log(x) = 2 arctanh((x-1)/(x+1)) */
n = (1 - n)/(n + 1);
now = term = n;
n *= n;
sm = 0;
for ( i = 3 ; ; i += 2 ){
sm += now;
term *= n;
now = term / i;
if ( now < 1e-17 ) break;
}
lgVal -= 2*sm;
if ( flag == -1 ) lgVal = -lgVal;
return lgVal;
}
किसी भी सुझाव या आलोचना की सराहना की है।
double series_ln_better(double n){ /* n = e^a * b, where a is an non-negative integer */
double lgVal = 0, term, now, sm;
int i, flag = 1;
if ( n == 0 ) return -1./0.; /* -inf */
if ( n < 0 ) return 0./0.; /* NaN*/
if ( n < 1 ) n = 1.0 / n, flag = -1; /* for extremely small n, use e^-x = 1/n */
/* the cutoff iteration is 650, as over e**650, term multiplication would
overflow. For larger numbers, the loop dominates the arctanh approximation
loop (with having 13-15 iterations on average for tested numbers so far */
for ( term = 1; term < n && lgVal < 650 ; term *= ee, lgVal++ );
if ( lgVal == 650 ){
n /= term;
for ( term = 1 ; term < n ; term *= ee, lgVal++ );
}
n /= term;
/* log(x) = 2 arctanh((x-1)/(x+1)) */
n = (1 - n)/(n + 1);
now = term = n;
n *= n;
sm = 0;
/* limiting the iteration for worst case scenario, maximum 24 iteration */
for ( i = 3 ; i < 50 ; i += 2 ){
sm += now;
term *= n;
now = term / i;
if ( now < 1e-17 ) break;
}
lgVal -= 2*sm;
if ( flag == -1 ) lgVal = -lgVal;
return lgVal;
}