C # tail recursion (continued)

Source: Internet
Author: User

 

Today, I read the final implementation code in the following article, but I am still not satisfied with it: the introduction of a Data Structure RecFunc, which is not very necessary for users <>, the code you need to define is like this:

 

(Rec, I, n, a, B) => (n <3? 1: (I = n? A + B: rec. Callback (I + 1, n, B, a + B )))

From the caller's point of view, the following code is easier to understand than above (without self, I am embarrassed to say that I have learned python ):

 

(Self, I, n, a, B) => (n <3? 1: (I = n? A + B: self (I + 1, n, B, a + B )))

Should I inherit the class from Delegate? However, C # cannot directly inherit this special class. Maybe you can use Delegate. CreateDelegate to create a Delegate object for combination? In this direction, we thought of directly creating an anonymous delegate.

 

So I modified the code again, and it was a little short and cool. The Code wrapped in tail recursion is as follows:

 

Public static Func <T1, T2, T3, T4, TResult> TailRecursive <T1, T2, T3, T4, TResult>

(Func <T1, T2, T3, T4, TResult>, T1, T2, T3, T4, TResult> func)

{

Return (p1, p2, p3, p4) =>

{

Bool callback = false;

Func <T1, T2, T3, T4, TResult> self = (q1, q2, q3, q4) =>

{

P1 = q1;

P2 = q2;

P3 = q3;

P4 = q4;

Callback = true;

Return default (TResult );

};

Do

{

Var result = func (self, p1, p2, p3, p4 );

If (! Callback)

{

Return result;

}

Callback = false;

} While (true );

};

}

In addition, the general recursive packaging method is added:

 

Public static Func <T1, T2, T3, T4, TResult> Recursive <T1, T2, T3, T4, TResult>

(Func <T1, T2, T3, T4, TResult>, T1, T2, T3, T4, TResult> func)

{

Func <T1, T2, T3, T4, TResult> self = null;

Self = (p1, p2, p3, p4) => func (self, p1, p2, p3, p4 );

Return self;

}

After writing the code, we still need to test it. I tested and compared the performance of the calculation of the Fib series in three ways: (1) the most basic method of recursive calling (2) use the above Recursive <> (3) use the above TailRecursive <> tail recursion.

 

The first two types are common recursion and can be executed due to the call stack restriction Fib (10000), but Fib (20000) overflows the stack. The third method is tail recursion. It is no problem to call Fib (20000), that is, Fib (10000000) is also executed instantly.

 

Data is always supported in the test. The test just showed that the number of milliseconds recorded by Stopwatch in the first two methods Fib (10000) is 0, and the performance of the three methods cannot be compared based on the time spent. So I added a very evil test code, wasting CPU time:

 

// External Initialization

Int x = 10000;

Var s = x. ToString ();

// Recursive loop

X =-x;

For (int j = 0; j <Math. Abs (x); j ++)

{

S = (s + x. ToString (). Substring (0, 5 );

}

I expect this code will not be optimized by the compiler or JIT, right? Indeed, after the addition, the time comparison is obvious:

 

Normal

Fib (100) =-980107325 (206 MS)

Fib (1000) = 1556111435 (2419 MS)

Fib (10000) = 1242044891 (65435 MS)

/////////////////////////////////////

Recursive

Fib (100) =-980107325 (192 MS)

Fib (1000) = 1556111435 (2735 MS)

Fib (10000) = 1242044891 (103156 MS)

/////////////////////////////////////

TailRecursive

Fib (100) =-980107325 (186 MS)

Fib (1000) = 1556111435 (1889 MS)

Fib (10000) = 1242044891 (18969 MS)

We can see that in the case of a large number of recursion times, tail recursion does have a great advantage in performance. Unexpectedly, simple packaging like Recursive actually reduces a lot of performance. I wonder which Eldest Brother can look at the test code to see where the problem is? Maybe I figured it out one day, so I can write another article later. <continue 2> haha

 

Test code

Static void Main (string [] args) {Console. writeLine ("Normal"); int x = 10000; var s = x. toString (); GC. collect (); GC. waitForPendingFinalizers (); Func <int, int> fiber 1 = null; fiber 1 = (I, n, a, B) => {x =-x; for (int j = 0; j <Math. abs (x); j ++) {s = (s + x. toString ()). substring (0, 5);} return (n <3? 1: (I = n? A + B: fib1 (I + 1, n, B, a + B) ;}; Action <int> Fib1 = n =>{ Console. write ("Fib ({0}) =", n); var sw = System. diagnostics. stopwatch. startNew (); var result = fig (3, n, 1, 1); sw. stop (); Console. writeLine ("{0} ({1} MS)", result, sw. elapsedMilliseconds);}; fiber 1 (100); fiber 1 (1000); fiber 1 (10000); Console. writeLine ("///////////////////////////////////// "); console. writeLine ("Recursive"); GC. collect (); GC. waitForPendingFinalizers (); var fib2 = Recursive <int, int> (self, I, n, a, B) => {x =-x; for (int j = 0; j <Math. abs (x); j ++) {s = (s + x. toString ()). substring (0, 3);} return (n <3? 1: (I = n? A + B: self (I + 1, n, B, a + B) ;}); Action <int> Fib2 = n =>{ Console. write ("Fib ({0}) =", n); var sw = System. diagnostics. stopwatch. startNew (); var result = fig (3, n, 1, 1); sw. stop (); Console. writeLine ("{0} ({1} MS)", result, sw. elapsedMilliseconds);}; fiber 2 (100); fiber 2 (1000); fiber 2 (10000); Console. writeLine ("///////////////////////////////////// "); console. writeLine ("TailRecursive"); GC. coll Ect (); GC. waitForPendingFinalizers (); var fib3 = TailRecursive <int, int> (self, I, n, a, B) =>{ x =-x; for (int j = 0; j <Math. abs (x); j ++) {s = (s + x. toString ()). substring (0, 3);} return (n <3? 1: (I = n? A + B: self (I + 1, n, B, a + B) ;}); Action <int> Fib3 = n =>{ Console. write ("Fib ({0}) =", n); var sw = System. diagnostics. stopwatch. startNew (); var result = fig (3, n, 1, 1); sw. stop (); Console. writeLine ("{0} ({1} MS)", result, sw. elapsedMilliseconds);}; fiber 3 (100); fiber 3 (1000); fiber 3 (10000 );}

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.