Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Recursion 使用MIPS的双递归_Recursion_Mips - Fatal编程技术网

Recursion 使用MIPS的双递归

Recursion 使用MIPS的双递归,recursion,mips,Recursion,Mips,我试图为函数f(n)=2f(n-1)+3f(n-2)+1实现双递归。我能够理解奇异递归并实现它的2f(n-1)+1部分,但我无法理解如何实现第二部分。以下是我的单数递归工作代码: .data prompt1: .asciiz "Enter the value for the recursive function f(n) = 2f(n-1)+3f(n-2)+1: " prompt2: .asciiz "Result: " numberEntered: .word 0 answer: .word

我试图为函数
f(n)=2f(n-1)+3f(n-2)+1实现双递归。我能够理解奇异递归并实现它的
2f(n-1)+1
部分,但我无法理解如何实现第二部分。以下是我的单数递归工作代码:

.data
prompt1: .asciiz "Enter the value for the recursive function f(n) = 2f(n-1)+3f(n-2)+1:  "
prompt2: .asciiz "Result: "
numberEntered: .word 0
answer: .word 0

.text

main:
#Ask for the value
li $v0 4
la $a0, prompt1
syscall

#enter value
li $v0, 5
syscall

sw $v0, numberEntered  #stores the number

# call the function
lw $a0, numberEntered
jal function
sw $v0, answer

#Print out the result
li $v0 4
la $a0, prompt2
syscall

lw $a0, answer
li $v0, 1
syscall

li $v0, 10
syscall

.globl function
function:
subu $sp, $sp, 8
sw $ra, ($sp)
sw $s0, 4($sp)

#base case
li $v0, 1
beq $a0, $zero, done

#calling f(n-1)
move $s0, $a0
sub $a0, $a0, 1
jal function

#calculations occur here
mul $v0, $v0, 2
addi $v0, $v0, 1

done:

lw $ra, ($sp)
lw $s0, 4($sp)
addi $sp, $sp, 8

jr $ra  #returns
我尝试将下一部分的地址加载到堆栈中的计算部分,但我无法找到使其工作的实现。我必须“卷起”这堆东西两次吗?一次当前状态如何,一次在计算部分?我想不出来,任何帮助都将不胜感激

相当不错的努力

回答您的问题:您只需在
函数
项中建立一个堆栈框架,并在最后从中恢复

我确实需要稍微调整
$s0
的用途,以存储一个中间值,并将其添加到堆栈帧中存储的值中(即堆栈帧现在是3个字,而不是2个字)

不管怎样,这是正确的代码。我试着对它稍加注释(在我看来,在asm中,没有“太多注释”这样的事情)。[请原谅这种不必要的风格清理]:

    .data
prompt1:    .asciiz     "Enter the value for the recursive function f(n) = 2f(n-1)+3f(n-2)+1:  "
prompt2:    .asciiz     "Result: "
numberEntered:  .word   0
answer:     .word       0

    .text

main:
    # Ask for the value
    li      $v0,4
    la      $a0,prompt1
    syscall

    # enter value
    li      $v0,5
    syscall

    sw      $v0,numberEntered       # stores the number

    # call the function
    lw      $a0,numberEntered
    jal     function
    sw      $v0,answer

    # Print out the result
    li      $v0,4
    la      $a0,prompt2
    syscall

    lw      $a0,answer
    li      $v0,1
    syscall

    li      $v0,10
    syscall

    .globl  function

# function -- calculation
# v0 -- return value
# a0 -- current n value
# s0 -- intermediate result
function:
    subi    $sp,$sp,12              # establish our stack frame

    sw      $ra,8($sp)              # save return address
    sw      $a0,4($sp)              # save n
    sw      $s0,0($sp)              # save intermediate result

    # base case
    # NOTE: with the addition of n-2, the "beq" was insufficient
    li      $v0,1
    ble     $a0,$zero,done

    # calling f(n-1)
    sub     $a0,$a0,1               # get n-1
    jal     function

    # NOTE: these could be combined into a single instruction
    mul     $v0,$v0,2               # get 2f(n-1)
    move    $s0,$v0                 # save it

    # calling f(n-2)
    sub     $a0,$a0,1               # get n-2
    jal     function

    mul     $v0,$v0,3               # get 3f(n-2)

    # get 2f(n-1) + 3f(n-2) + 1
    add     $v0,$s0,$v0
    add     $v0,$v0,1

done:
    lw      $ra,8($sp)              # restore return address
    lw      $a0,4($sp)              # restore n
    lw      $s0,0($sp)              # restore intermediate result

    addi    $sp,$sp,12              # pop stack frame

    jr      $ra                     # returns

更新:

这个解决方案比我想象的要简单得多

这可能是因为asm[或C]中堆栈帧的处理方式

考虑一个现代C程序:

int
whatever(int n)
{
    int x;

    // point A
    x = other(1);

    // do lots more stuff ...

    {
        // point B
        int y = other(2);

        // do lots more stuff ...

        // point C
        n *= (x + y);
    }

    // do lots more stuff ...

    n += ...;

    return n;
}
C编译器将在进入
任何
时建立一个堆栈框架,该框架将为
x
y
保留空间,即使
y
只在很久以后设置。大多数C程序员没有意识到这一点

在解释语言(例如
java
python
等)中,
y
的空间在执行
点B
处的代码之前不会保留。而且,当
y
超出范围时,[在
点C
之后],他们将[通常]解除分配它

大多数C程序员认为使用作用域声明[如
y
]可以节省堆栈空间。(即)在作用域块中,编译器将增加堆栈帧大小以适应
y
,并在不再需要
y
时再次收缩堆栈帧

这根本不正确。C编译器将设置堆栈框架并为所有函数作用域变量保留空间,即使这些变量在函数中声明较晚或在内部作用域内[like
y
]

这正是我们在您的
函数中所做的。这是正确的,即使在函数中间之前,
$s0
不需要/利用堆栈空间[offset 0]

因此,我猜想,您使用其他语言的经验(有效地)动态地保留了空间,或者关于C的常识可能会让您找到一个更复杂的模型,来描述您认为需要的内容。因此,你最初的问题是:我必须“卷起”堆栈两次吗


我还应该提到,
函数
的调用约定不符合ABI。如果它是自包含的(即不调用任何其他内容),则这是非常好的。也就是说,在asm中,对于“叶”函数,我们可以定义我们想要的任何内容


原因是
$a0
调用可能会被被叫方修改/丢弃。我们从堆栈中保存/恢复了它,但是调用另一个函数可能会把事情搞砸。补救方法就是使用另一个寄存器来保存值[或保存/恢复到堆栈帧中的一个额外位置],因此如果
函数
最终调用其他函数,则需要做更多的工作。

感谢您的帮助!这个解决方案比我想象的要简单得多。不客气!在进一步思考了您的原始问题[关于第二个堆栈]之后,我添加了关于堆栈框架模型的更多解释。我还添加了一些关于Abi的内容,这现在更有意义了,谢谢你所做的一切!你超出了我的要求。我发现你的代码中有一个小错误。在注释#get 2f(n-1)+3f(n-2)+1下的行中,应添加$v0、$s0、$v0,然后添加$v0、$v0,1。您使用$s0跟踪一个值,但在最后的计算中忽略了它。我还介绍了一个次要的基本情况,使整个工作正常。有什么地方我应该发布代码吗?你完全正确--我错过了。我将为后代编辑我的代码。您可以编辑问题并将其添加到那里。但是,总的来说,在这里,你完全可以为自己的问题提供答案。大多数老年人都不介意。但是,如果没有答案,OP通常会自己解决问题。或者,如果有多个不完整的答案(例如,4个答案,每个答案只能解决25%),当组合起来时,给OP答案[可能有OP的一些额外代码]。对于一些小的调整,回复者(他修复了)的评论通常是一种方式。