For tail recursion, many people's understanding is limited to its combination of recursion and tail call, which is more efficient than normal recursion. As for why efficiency is high and where it is high, it may not be further explored. When executing function B, most of the stack frames of function A are useless and can be modified or overwritten. This can be used by the compiler to optimize the function. After function B is executed, it is directly returned to the caller of function.
For tail recursion, many people's understanding is limited to its combination of recursion and tail call, which is more efficient than normal recursion. Why is efficiency high .?
End call
To say tail recursion, we must first talk about tail calling. I understand that the end call is probably like this:
- Function A Calls function B.
- Function A returns immediately after Function B is executed.
- That is to say, calling function B (and returning execution results) is the last thing function A does.
- After function B is executed, function A is executed.
Therefore, when executing function B, most of the stack frames of function A are useless and can be modified or overwritten. This can be used by the compiler for optimization. After function B is executed, it is directly returned to the caller of function .?
Here, we need to note that it comes from compiler optimization .? This optimization may be of little significance for general tail calls, but it is very important for tail recursion .?
Tail recursion
Tail recursion is A kind of recursion based on the form of tail call, which is equivalent to function B as mentioned above .?
Some problems with normal recursion are that each layer of recursion consumes a certain amount of stack space. too deep recursion may also cause Stack Overflow and function calls, avoiding pushing to pop, consumed time .?
The tail call is used to implement recursion, that is, tail recursion, which can theoretically solve the problem of normal recursion. Because the stack frames used by the next layer of recursion can overlap with the previous layer (implemented using jmp), local variables can be reused without consuming additional stack space, no push or pop .?
Again, the actual effect of it comes from the optimization of the compiler ). When tail recursion is used, the compiler will optimize recursive calls into loops if it finds it appropriate. Currently, most compilers support tail recursion optimization. Some languages are even very dependent on tail recursion (tail call), such as erlang or other functional languages (it is said that they are used to better process the continuation-passing style ).?
If there is no optimization, there is no advantage in tail recursion for function calling, and there are even disadvantages-the code is not intuitive to write .?
The optimization capabilities of modern compilers are very powerful. in many cases, the compiler is not very soft (so it has volatile ). But sometimes the compiler is very proud. you need to give it a signal to optimize it. Tail recursion is equivalent to passing a signal to the compiler. how can I optimize it !?
Test
To verify tail recursion optimization, you can write a small program for testing. In VS2010, the/O1 or above optimization options will be used, and the tail recursive optimization will generally be performed. In Gcc3.2.2 (old version), The-O2 optimization option is generally used.
First, let's look at normal recursion:
// Recursive int factorial (int n) {if (n <= 2) {return 1;} else {return factorial (n-1) + factorial (n-2 );}}
Its assembly code:
00401371push %ebp00401372mov %esp,%ebp00401374push %ebx00401375sub $0x14,%esp00401378cmpl $0x2,0x8(%ebp)0040137Cjg 0x401385
0040137Emov $0x1,%eax00401383jmp 0x4013a4
00401385mov 0x8(%ebp),%eax00401388dec %eax00401389mov %eax,(%esp)0040138Ccall 0x401371
00401391mov %eax,%ebx00401393mov 0x8(%ebp),%eax00401396sub $0x2,%eax00401399mov %eax,(%esp)0040139Ccall 0x401371
004013A1lea (%ebx,%eax,1),%eax004013A4add $0x14,%esp004013A7pop %ebx004013A8leave004013A9ret
In the positions of 0040138C and 0040139C, we can see that recursion still uses the call Command. how does tail recursion deal with the assembly angle?
Tail recursion:
int factorial_tail(int n,int acc1,int acc2){ if (n < 2) { return acc1; } else { return factorial_tail(n-1,acc2,acc1+acc2); }}
Its assembly code:
00401381push %ebp00401382mov %esp,%ebp00401384sub $0x18,%esp00401387cmpl $0x1,0x8(%ebp)0040138Bjg 0x401392
0040138Dmov 0xc(%ebp),%eax00401390jmp 0x4013b2
00401392mov 0x10(%ebp),%eax00401395mov 0xc(%ebp),%edx00401398lea (%edx,%eax,1),%eax0040139Bmov 0x8(%ebp),%edx0040139Edec %edx0040139Fmov %eax,0x8(%esp)004013A3mov 0x10(%ebp),%eax004013A6mov %eax,0x4(%esp)004013AAmov %edx,(%esp)004013ADcall 0x401381
004013B2leave004013B3ret
In the 00401390 position, tail recursion directly uses jmp for loop jump.
How to view the C language program assembly? Let's take a look at this separate article: how to view the assembly Code of the program under Code: Blocks
Additional reading
The topic list of this article is as follows:
- Recursive: recursive thinking
- Recursion: two conditions that must be met by recursion
- Recursion: recursive determination of string-to-text phenomena
- Recursive: recursive implementation of binary search algorithms
- Recursion: the efficiency of recursion
- Recursion: recursion and loop
- Let's talk about recursion: Is loop and iteration the same thing?
- Recursive computing and iterative computing
- On Recursion: Learn about tail recursion from Fibonacci
- Recursive: Tail recursion and CPS
- Recursion: add more knowledge about Continuation.
- Recursion: Tail recursion in PHP and its optimization
- Recursion: Tail recursion optimization from the perspective of Assembly
This article is available at http://www.nowamagic.net/librarys/veda/detail/2336.