Mips/assembly 递归语言求幂
Mips/assembly language exponentiation recursivley
我正在尝试将此代码实现为汇编语言。我无法通过将用户的两个输入保存到堆栈的想法来解决这个问题。
这是递归操作的代码:
#include <iostream>
using namespace std;
int recursiveFunction ( int base, int power);
int main(int argc, const char * argv[])
{
int base = 0;
int power = 0;
int result = 0;
std::cout << "Enter the base to compute the exponential equation";
std::cout << endl;
std::cin >> base;
std::cout<< "Enter the power for the base to conduct solution";
std::cout<< endl;
std::cin>> power;
result = recursiveFunction(base,power);
std::cout<<"The result of the following calculation is:" << result;
std::cout<<endl;
std::cout<<endl;
return 0;
}
int recursiveFunction(int base, int power)
{
if( power != 0)
{
return(base*recursiveFunction(base, (power - 1)));
}
else
return 1;
}
何时使用堆栈space:
我们更愿意将局部变量(例如从 C/C++ 中的算法)映射到 CPU 寄存器,而不是堆栈位置;但是,许多寄存器无法在函数调用后继续存在。堆栈用于分配与调用相关的内存,这些内存将在后续函数调用中保留下来。一些寄存器在函数调用后仍然存在,但需要明确的是,这是通过使用堆栈内存来保留这些寄存器的原始值以便以后可以恢复它们来确保的。
我们需要对局部变量进行分析,以确定哪些变量需要在函数调用中存活下来,因为这些变量需要特殊处理,需要堆栈内存。
例如,在 main
中,我们可以确定 power
不需要在函数调用后继续存在。变量 power
被定义为初始值 0 但没有人使用它——因此我们将忽略该初始化。接下来它被系统调用中的 return 值设置,然后立即作为递归函数的参数使用——但在递归调用之后没有被使用。因此,power
不需要在函数调用后仍然存在,可以简单地分配给一个临时寄存器(在函数调用后不会存在)。
对代码稍作修改,例如在递归调用后打印 power
值,将呈现相反的分析结果。
相同的分析实际上适用于 main
中的所有变量,因为从技术上讲,所有提示和输入都是通过系统调用完成的,这与常规函数调用不同——因为它们甚至保留了临时的寄存器除了那些涉及参数传递和 return 值的寄存器:通常这意味着 $a0
和 $v0
不能依赖于在系统调用中存活,因为它们通常是系统调用参数传递的定义。然而,可以依赖其他临时寄存器在系统调用中存活下来。因此,您可以在 main
中使用 $t1
、$t2
、$t3
,而无需使用 base
、power
、result
任何堆栈 space 或内存加载和存储。 base
是否需要在 power
的提示和输入中存活下来,但按照上述,这两个操作是通过系统调用完成的,而不是常规函数调用,这意味着base
也不需要堆栈位置。
识别必须在(非系统调用)函数调用中存活的局部变量的分析在 recursiveFunction
中尤为重要。 base
变量被定义为参数,并在 函数调用(恰好是递归的)之后使用 。它用作乘法的操作数,乘法的另一个操作数是函数调用的 return 值。对于此分析,recursiveFunction
中的函数调用本身是递归的并不重要,因为如果调用其他(非递归)函数,则此分析不会改变 - 仅调用另一个函数是有问题的.因为它需要在递归调用中存活下来,所以应该将它存储到堆栈内存中(当它的值仍然可用时在递归调用之前)并在需要时重新加载(在递归调用之后)。
power
不需要在 recursiveFunction
内的调用中存活。因此,它应该简单地递减,仅此而已——不需要堆栈内存。
最后,大多数非主要功能 return 到他们的调用者。这是通过最初向它们传递一个参数来实现的,该参数指示在它们完成时要恢复(将控制权转移到)的代码位置。该参数在高级语言中是隐藏的,但在 MIPS 中是在 $ra
寄存器中。它作为参数传递并在函数的最后使用,在 returning 中传递给它的调用者。因此,它必须在函数实现完成的任何函数调用中存活下来,因为任何函数调用本身都会重新调整该寄存器的用途(用于调用自己的 activity)。
此外,在不需要时使用堆栈 space 是可以的(正确,但可能效率低下),即当变量不需要在函数调用中存活时。
(我知道有优化机会,但我觉得目前不在主题范围内。)
堆栈的使用方法space:
首先,分配一些堆栈 space:使用 addiu $sp, $sp, -X
分配任意数量,其中 X 是一个常数,其值为 4 或更大,也是 4 的倍数。所有你想要的单词中的字节,并用一条 addiu
指令分配它们。
新分配的堆栈 space 将从 0($sp)
开始。如果您分配了超过 4 个字节(例如 12 个字节),那么您有 0($sp)
(又名 $sp+0)作为第一个字的地址,4($sp)
、8($sp)
作为连续的可用字.这些内存位置供您在函数运行期间使用(例如 main
)。 “你的”是指它们属于在激活期间分配它们的函数的激活。 (递归函数可能在堆栈上有多个激活。)
你可以把新的栈位置映射到函数中的局部变量,当C/C++代码使用相应的变量时使用相应的内存位置。
确保在 return 调用函数的调用者之前释放堆栈 space。如果您使用系统调用 10 退出程序,则不需要释放 space;然而,如果你想 return 给调用者,你必须在 returning 之前将堆栈指针恢复到它的原始值,否则调用者将找不到他们自己的基于堆栈的变量,如果他们也使用堆栈.这将适用于 recursiveFunction
,例如,如果您还想在那里使用堆栈 space。
堆栈指针下方的 Space 是“未分配的”,可以自由分配,然后由任何函数以这种方式使用。函数调用链正在使用堆栈指针及其上方的堆栈 space,无论哪个函数在入口处分配了 space,在退出时也必须释放相同的 space。
我正在尝试将此代码实现为汇编语言。我无法通过将用户的两个输入保存到堆栈的想法来解决这个问题。
这是递归操作的代码:
#include <iostream>
using namespace std;
int recursiveFunction ( int base, int power);
int main(int argc, const char * argv[])
{
int base = 0;
int power = 0;
int result = 0;
std::cout << "Enter the base to compute the exponential equation";
std::cout << endl;
std::cin >> base;
std::cout<< "Enter the power for the base to conduct solution";
std::cout<< endl;
std::cin>> power;
result = recursiveFunction(base,power);
std::cout<<"The result of the following calculation is:" << result;
std::cout<<endl;
std::cout<<endl;
return 0;
}
int recursiveFunction(int base, int power)
{
if( power != 0)
{
return(base*recursiveFunction(base, (power - 1)));
}
else
return 1;
}
何时使用堆栈space:
我们更愿意将局部变量(例如从 C/C++ 中的算法)映射到 CPU 寄存器,而不是堆栈位置;但是,许多寄存器无法在函数调用后继续存在。堆栈用于分配与调用相关的内存,这些内存将在后续函数调用中保留下来。一些寄存器在函数调用后仍然存在,但需要明确的是,这是通过使用堆栈内存来保留这些寄存器的原始值以便以后可以恢复它们来确保的。
我们需要对局部变量进行分析,以确定哪些变量需要在函数调用中存活下来,因为这些变量需要特殊处理,需要堆栈内存。
例如,在 main
中,我们可以确定 power
不需要在函数调用后继续存在。变量 power
被定义为初始值 0 但没有人使用它——因此我们将忽略该初始化。接下来它被系统调用中的 return 值设置,然后立即作为递归函数的参数使用——但在递归调用之后没有被使用。因此,power
不需要在函数调用后仍然存在,可以简单地分配给一个临时寄存器(在函数调用后不会存在)。
对代码稍作修改,例如在递归调用后打印 power
值,将呈现相反的分析结果。
相同的分析实际上适用于 main
中的所有变量,因为从技术上讲,所有提示和输入都是通过系统调用完成的,这与常规函数调用不同——因为它们甚至保留了临时的寄存器除了那些涉及参数传递和 return 值的寄存器:通常这意味着 $a0
和 $v0
不能依赖于在系统调用中存活,因为它们通常是系统调用参数传递的定义。然而,可以依赖其他临时寄存器在系统调用中存活下来。因此,您可以在 main
中使用 $t1
、$t2
、$t3
,而无需使用 base
、power
、result
任何堆栈 space 或内存加载和存储。 base
是否需要在 power
的提示和输入中存活下来,但按照上述,这两个操作是通过系统调用完成的,而不是常规函数调用,这意味着base
也不需要堆栈位置。
识别必须在(非系统调用)函数调用中存活的局部变量的分析在 recursiveFunction
中尤为重要。 base
变量被定义为参数,并在 函数调用(恰好是递归的)之后使用 。它用作乘法的操作数,乘法的另一个操作数是函数调用的 return 值。对于此分析,recursiveFunction
中的函数调用本身是递归的并不重要,因为如果调用其他(非递归)函数,则此分析不会改变 - 仅调用另一个函数是有问题的.因为它需要在递归调用中存活下来,所以应该将它存储到堆栈内存中(当它的值仍然可用时在递归调用之前)并在需要时重新加载(在递归调用之后)。
power
不需要在 recursiveFunction
内的调用中存活。因此,它应该简单地递减,仅此而已——不需要堆栈内存。
最后,大多数非主要功能 return 到他们的调用者。这是通过最初向它们传递一个参数来实现的,该参数指示在它们完成时要恢复(将控制权转移到)的代码位置。该参数在高级语言中是隐藏的,但在 MIPS 中是在 $ra
寄存器中。它作为参数传递并在函数的最后使用,在 returning 中传递给它的调用者。因此,它必须在函数实现完成的任何函数调用中存活下来,因为任何函数调用本身都会重新调整该寄存器的用途(用于调用自己的 activity)。
此外,在不需要时使用堆栈 space 是可以的(正确,但可能效率低下),即当变量不需要在函数调用中存活时。
(我知道有优化机会,但我觉得目前不在主题范围内。)
堆栈的使用方法space:
首先,分配一些堆栈 space:使用 addiu $sp, $sp, -X
分配任意数量,其中 X 是一个常数,其值为 4 或更大,也是 4 的倍数。所有你想要的单词中的字节,并用一条 addiu
指令分配它们。
新分配的堆栈 space 将从 0($sp)
开始。如果您分配了超过 4 个字节(例如 12 个字节),那么您有 0($sp)
(又名 $sp+0)作为第一个字的地址,4($sp)
、8($sp)
作为连续的可用字.这些内存位置供您在函数运行期间使用(例如 main
)。 “你的”是指它们属于在激活期间分配它们的函数的激活。 (递归函数可能在堆栈上有多个激活。)
你可以把新的栈位置映射到函数中的局部变量,当C/C++代码使用相应的变量时使用相应的内存位置。
确保在 return 调用函数的调用者之前释放堆栈 space。如果您使用系统调用 10 退出程序,则不需要释放 space;然而,如果你想 return 给调用者,你必须在 returning 之前将堆栈指针恢复到它的原始值,否则调用者将找不到他们自己的基于堆栈的变量,如果他们也使用堆栈.这将适用于 recursiveFunction
,例如,如果您还想在那里使用堆栈 space。
Space 是“未分配的”,可以自由分配,然后由任何函数以这种方式使用。函数调用链正在使用堆栈指针及其上方的堆栈 space,无论哪个函数在入口处分配了 space,在退出时也必须释放相同的 space。