我正在尝试在MIPS程序集中实现递归模幂运算程序。该程序允许用户输入三个正数x,n和p,并输出(x ^ n)mod p。我能够用Java编写代码,但是我很难将代码转换为MIPS Assembly。这是我的Java代码:
int modPow(int x, int n, int p) {
x = x%p;
if (n == 0)
return 1;
else if (n == 1)
return x;
else if (n%2 == 0)
return modPow(x*x%p, n/2, p);
else
return x*modPow(x, n-1, p)%p;
}
我意识到我最大的问题是在MIPS中调用方法,特别是递归。以下是我到目前为止的情况:
.text
main:li $v0, 5 #store x in $v0
syscall
move $s0, $v0 #move x to $s0
li $v0, 5 #store n in $v0
syscall
move $s1, $v0 #move n to $s1
li $v0, 5 #store p in $v0
syscall
move $s2, $v0 #move p to $s2
div $s0, $s2
mfhi $s0 #x = x % p
bne $s1, $zero, L1 #Branch to first ElseIf if !(n==0)
li $a0, 1 #return value stored as 1
li $v0, 1 #output 1 (what is stored in $a0)
syscall
L1: li $t0, 1 #$t0 = 1
bne $s1, $t0, L2 #Branch to second ElseIf if !(n==1)
move $a0, $s1 #$a0 = n
li $v0, 1 #output n (stored in $a0)
syscall
L2: li $t0, 2 #t0 = 2
div $s1, $t0
mfhi $t0 #$t0 = n % 2
bne $t0, $zero, L3 #Branch to else if !(n%2==0)
mflo $s1 #$s1 = floor(n/2)
mult $s0, $s0 #x * x
mfhi $s0 #x = x * x
div $s0, $s2
mfhi $s0 #$s0 = (x * x) % p
jal main
L3: li $t0, 1 #$t0 = 1
sub $s1, $t0 #n = n-1
jal main
mult $s0, $a0 #x * mod(x, n-1, p)
mfhi $s0 #x = x * mod(x, n-1, p)
div $s0, $s2
mfhi $a0 #x = x * mod(x, n-1, p) % p stored in $a0
li $v0, 1
syscall
我使用系统调用指令来获取用户的输入并将内容输出给用户。做大部分算术都很简单,我的大多数麻烦都是用这些方法调用,特别是在递归中。任何人都可以帮助我吗?
答案 0 :(得分:0)
在您的Java代码中,您递归调用modPow()
,它运行其函数参数,但在汇编代码中,您将递归main()
,它执行I / O操作。这可能不是你想要的。定义标签modPow:
并在那里实现您的功能。此外,Java代码比它需要的更复杂,这反过来又难以实现它。
1.如果if
条件以return
声明结尾,则不需要else
2.如果你不打算使用它,你不需要计算模数
3.您不需要在两个位置计算模数(在函数体和递归调用中)。但是做想要计算返回值的模数
4.对于所有n,pow(1,n)为1
5.对于所有n!= 0,pow(0,n)为0(可论证,但if (!n)
已涵盖)
尝试:
int modPow(int x, int n, int p)
{
if (!n)
return 1;
x %= p;
if ( !x || x == 1 || n ==1 )
return x;
if (n % 2)
return x*modPow(x, n-1, p)%p;
return modPow(x*x, n/2, p);
}
也就是说,要在MIPS上调用函数,需要在堆栈中保存链接寄存器的当前值(返回地址):
addi $sp, $sp, -4 #on 32-bit MIPS, 4 byte word
sw $ra, ($sp) #save return address of current function
... #load function arguments to $a0...
jal functionToCall #call
... #use return value in $v0
lw $ra, ($sp) #restore return address
addi $sp, $sp, 4 #restore stack-pointer
jr $ra #return
答案 1 :(得分:0)
递归有两个规则:
保存您的寄信人地址
跳转并链接(jal)到您要调用的方法
我认为您的代码存在的问题是您似乎没有做这些