不使用分支指令的 n 个自然数(1 到 n)的 MIPS 代码总和

MIPS CODE sum of n natural numbers (1 to n) WITHOUT USING BRANCH INSTRUCTION

.data
input: .asciiz "Enter limit for the sum of natural number = "
show: .asciiz " \n sum of natural numbers are =   "

.text
main:
#get the integer input from user
    li $v0, 4
    la $a0, input
    syscall
    li $v0, 5
    syscall
    move $s5, $v0
    li $v0, 1
    move $a0, $s5
    syscall
    
    addi $t5, $t5, 0
iteration:
    blt $t5, $s5, increment 
    j end
increment:  
    add $s2, $s2, $t5
    addi $t5, $t5, 1
j iteration
end:    
    li $v0, 4
    la $a0, show
    syscall  
    
    li $v0, 1
    move $a0, $s2
    syscall

好的,所以我知道如何使用分支指令通过用户输入获取 n 个自然数的总和,但我的问题是:“如何在不使用分支指令的情况下执行相同的程序(bge、bltv bne 等)"

1..n的总和等于(n*(n+1))/2

在伪代码中:

temp := (input + 1)
temp := (temp * input)
result := (temp >> 1)

当有一个公式来计算某些东西时,就像所讨论的特定问题陈述的情况一样,这通常是最好的方法。


但是,如果您在不使用经典条件分支指令的情况下更广泛地寻找条件执行,则可以通过寄存器指令使用无条件分支,使用 MIPS,jr <reg>,跳转寄存器。

背景:条件分支指令测试一个条件,然后分支或下降到下一条指令——也就是说,有两个目的地(对于后续执行的指令流)的选择是动态的。

虽然通过寄存器的跳转总是会改变控制流并且永远不会“失败”,但根据定义,通过寄存器的跳转可以通过在该指令之前计算一个(多个)来设置任意数量的不同目的地.

查看它的简单方法是计算以下内容:

    done := i < N
    whereToGo := (&doneLabel * done) + (&LoopTop * !done)

首先,计算一个布尔值,其值为 1 或 0。在上面的 whereToGo 计算中,两项中只有一项为非零,其中使用乘法恒等式 1 case 和 null 因子 0,在另一种情况下。

(请注意,在 MIPS 中,形成布尔值的 < 操作是通过 slt 和类似的操作完成的,特别是在不使用条件分支指令的情况下。)

这是一个更大的例子,使用循环:

    ... // loop initialization
loopTop:
    <do something>
    done := i < N
    <reg> := (&doneLabel * done) + (&LoopTop * !done)
    jr <reg>
 doneLabel:
    ...

对于那些希望避免乘法来完成此操作的人,我们可以使用 AND 代替。要使用 AND 运算,我们不需要布尔值 1 与 0,而是经过更改的布尔值 -1 与 0。对于 AND,-1 是标识,0 是空因子。

    done := i < N             // produces 1 or 0 result (for true, false, resp.)
    mask := done - 1          // produces 0 or -1 result
    whereToGo := (&doneLabel & ~mask) | (&LoopTop & notDone)

在上面,当 done 为真时,mask 将为 0(我们想退出,所以我们在该术语上使用 ~mask),而它会当 done 为 false 时为 -1。

既然一项永远是0,那么加法,+与OR,|是等价的。


当然,可以使用更多项在更多目的地之间进行选择来推广这种方法,只要只有一个项的布尔值评估为同一性,而所有其他项都为空即可。