如何在 MIPS 中找到数组的最小值
How to find the minimum value of an array in MIPS
这是我的代码,我无法获得正确的输出。我哪里出错了?我最初将 min 设置为零,然后检查数组是否小于或等于该值,然后如果是我跳转到一个标签并将 min 的值设为数组的值,然后跳回迭代数组。
xyz: .word -8, 16, -32, 64, -128, 256
# int main(void)
#
# local variable register
# int *p $s0
# int *end $s1
# int min $s2
# int total $s3
#
.text
.globl main
main:
la $s0, xyz # p = foo
addi $s1, $s0, 24 # end = p + 6
add $s3, $zero, $zero # total = 0
add $s2, $zero, $zero # min = 0
L1:
beq $s0, $s1, L2 # if (p == end) goto L2
lw $t0, ($s0) # $t0 = *p
lw $t1, ($s2) # $t1 = min
slt $t2, $t1, $t0 # check if min is less than p
add $s3, $s3, $t0 # total += $t0
bne $t2, $zero, L3 # if min is less than p, go to L3
addi $s0, $s0, 4 # p++
j L1
L2:
add $v0, $zero, $zero # return value from main = 0
jr $ra
L3:
move $s2, $t0
j L1
好的,我发现了几个错误。我已经创建了三个版本并添加了输出系统调用,因此您可以看到结果[请原谅不必要的样式清理]:
这是带有错误注释的原始代码:
.data
xyz: .word -8,16,-32,64,-128,256
# int main(void)
#
# local variable register
# int *p $s0
# int *end $s1
# int min $s2
# int total $s3
#
.text
.globl main
main:
la $s0,xyz # p = foo
addi $s1,$s0,24 # end = p + 6
add $s3,$zero,$zero # total = 0
# NOTE/BUG: to find minimum, you want to init this to the first array
# element
# also, initializing with a minimum value (e.g. 0), or more correctly, the
# largest possible negative number (e.g. 0x80000000) implies a search for
# maximum
add $s2,$zero,$zero # min = 0
L1:
beq $s0,$s1,L2 # if (p == end) goto L2
lw $t0,($s0) # $t0 = *p
# NOTE/BUG: s2 is a register variable that contains "min" (e.g. int min)
# and is _not_ a pointer to a "min" variable in memory (e.g. int *min)
lw $t1,($s2) # $t1 = min
# NOTE/BUG: the the check should be reversed:
slt $t2,$t1,$t0 # check if min is less than p
add $s3,$s3,$t0 # total += $t0
bne $t2,$zero,L3 # if min is less than p, go to L3
# NOTE/BUG: this pointer increment is out of place (i.e. it does not
# get incremented if there is a jump to L3)
# this won't affect the min value, but it will double count the value in
# the total
addi $s0,$s0,4 # p++
j L1
L2:
add $v0,$zero,$zero # return value from main = 0
jr $ra
L3:
move $s2,$t0
j L1
这里是固定版本:
.data
xyz: .word -8,16,-32,64,-128,256
msg_min: .asciiz "min: "
msg_tot: .asciiz " total: "
msg_nl: .asciiz "\n"
# int main(void)
#
# local variable register
# int *p $s0
# int *end $s1
# int min $s2
# int total $s3
#
.text
.globl main
main:
la $s0,xyz # p = foo
addi $s1,$s0,24 # end = p + 6
add $s3,$zero,$zero # total = 0
lw $s2,0($s0) # min = xyz[0]
L1:
beq $s0,$s1,L2 # if (p == end) goto L2
lw $t0,0($s0) # $t0 = *p
addi $s0,$s0,4 # p++
add $s3,$s3,$t0 # total += $t0
slt $t2,$t0,$s2 # *p < min?
bne $t2,$zero,L3 # yes, fly
j L1
L2:
li $v0,4
la $a0,msg_min
syscall
li $v0,1
move $a0,$s2 # get min value
syscall
li $v0,4
la $a0,msg_tot
syscall
li $v0,1
move $a0,$s3 # get total value
syscall
li $v0,4
la $a0,msg_nl
syscall
# exit program
li $v0,10
syscall
L3:
move $s2,$t0 # set new/better min value
j L1
这是一个稍微更简洁的版本,我颠倒了分支的意义,并且能够稍微收紧循环。此外,我将标签更改为更能描述 role/function:
.data
xyz: .word -8,16,-32,64,-128,256
msg_min: .asciiz "min: "
msg_tot: .asciiz " total: "
msg_nl: .asciiz "\n"
# int main(void)
#
# local variable register
# int *p $s0
# int *end $s1
# int min $s2
# int total $s3
#
.text
.globl main
main:
la $s0,xyz # p = foo
addi $s1,$s0,24 # end = p + 6
add $s3,$zero,$zero # total = 0
lw $s2,0($s0) # min = xyz[0]
main_loop:
beq $s0,$s1,main_done # if (p == end) goto L2
lw $t0,0($s0) # $t0 = *p
addi $s0,$s0,4 # p++
add $s3,$s3,$t0 # total += $t0
slt $t2,$s2,$t0 # *p < min?
bne $t2,$zero,main_loop # no, loop
move $s2,$t0 # set new/better min value
j main_loop
main_done:
li $v0,4
la $a0,msg_min
syscall
li $v0,1
move $a0,$s2 # get min value
syscall
li $v0,4
la $a0,msg_tot
syscall
li $v0,1
move $a0,$s3 # get total value
syscall
li $v0,4
la $a0,msg_nl
syscall
# exit program
li $v0,10
syscall
更新:
thanks that helped a lot, but lw $t1,($s2)
doesnt work because lw will only work on pointers?
没错。请注意您是如何使用 s3
来保持 total
的。这就是代码使用 s2
来保存最小值的方式。我这样做[部分]是因为最高评论:
# int min $s2
要使用 lw
,置顶评论应该是:
# int *min $s2
要以原始方式使用 s2
,您需要如下内容:
min: .word 0
而且,您需要(在循环开始之前):
la $s2,min
而且,您必须 lw
和 sw
,这只会减慢速度。因此,除了已有的内容之外,您还需要添加一个额外的 lw
和一个额外的 sw
。
mips 有很多 寄存器[它的强项]。因此,它加快了速度,以在其中保留自动的、函数范围的变量。
但是,为了完整起见,这里有一个允许 lw
的版本。注意额外的内存访问。这很像用 -O0:
编译的 C 代码
.data
min: .word 0
xyz: .word -8,16,-32,64,-128,256
msg_min: .asciiz "min: "
msg_tot: .asciiz " total: "
msg_nl: .asciiz "\n"
# int main(void)
#
# local variable register
# int *p $s0
# int *end $s1
# int *min $s2
# int total $s3
#
.text
.globl main
main:
la $s0,xyz # p = foo
addi $s1,$s0,24 # end = p + 6
add $s3,$zero,$zero # total = 0
la $s2,min # point to min
lw $t4,0($s0) # fetch xyz[0]
sw $t4,0($s2) # store in min
main_loop:
beq $s0,$s1,main_done # if (p == end) goto L2
lw $t0,0($s0) # $t0 = *p
addi $s0,$s0,4 # p++
add $s3,$s3,$t0 # total += $t0
lw $t4,0($s2) # fetch min
slt $t2,$t4,$t0 # *p < min?
bne $t2,$zero,main_loop # no, loop
sw $t0,0($s2) # store new/better min value
j main_loop
main_done:
li $v0,4
la $a0,msg_min
syscall
li $v0,1
lw $a0,0($s2) # get min value
syscall
li $v0,4
la $a0,msg_tot
syscall
li $v0,1
move $a0,$s3 # get total value
syscall
li $v0,4
la $a0,msg_nl
syscall
# exit program
li $v0,10
syscall
这是我的代码,我无法获得正确的输出。我哪里出错了?我最初将 min 设置为零,然后检查数组是否小于或等于该值,然后如果是我跳转到一个标签并将 min 的值设为数组的值,然后跳回迭代数组。
xyz: .word -8, 16, -32, 64, -128, 256
# int main(void)
#
# local variable register
# int *p $s0
# int *end $s1
# int min $s2
# int total $s3
#
.text
.globl main
main:
la $s0, xyz # p = foo
addi $s1, $s0, 24 # end = p + 6
add $s3, $zero, $zero # total = 0
add $s2, $zero, $zero # min = 0
L1:
beq $s0, $s1, L2 # if (p == end) goto L2
lw $t0, ($s0) # $t0 = *p
lw $t1, ($s2) # $t1 = min
slt $t2, $t1, $t0 # check if min is less than p
add $s3, $s3, $t0 # total += $t0
bne $t2, $zero, L3 # if min is less than p, go to L3
addi $s0, $s0, 4 # p++
j L1
L2:
add $v0, $zero, $zero # return value from main = 0
jr $ra
L3:
move $s2, $t0
j L1
好的,我发现了几个错误。我已经创建了三个版本并添加了输出系统调用,因此您可以看到结果[请原谅不必要的样式清理]:
这是带有错误注释的原始代码:
.data
xyz: .word -8,16,-32,64,-128,256
# int main(void)
#
# local variable register
# int *p $s0
# int *end $s1
# int min $s2
# int total $s3
#
.text
.globl main
main:
la $s0,xyz # p = foo
addi $s1,$s0,24 # end = p + 6
add $s3,$zero,$zero # total = 0
# NOTE/BUG: to find minimum, you want to init this to the first array
# element
# also, initializing with a minimum value (e.g. 0), or more correctly, the
# largest possible negative number (e.g. 0x80000000) implies a search for
# maximum
add $s2,$zero,$zero # min = 0
L1:
beq $s0,$s1,L2 # if (p == end) goto L2
lw $t0,($s0) # $t0 = *p
# NOTE/BUG: s2 is a register variable that contains "min" (e.g. int min)
# and is _not_ a pointer to a "min" variable in memory (e.g. int *min)
lw $t1,($s2) # $t1 = min
# NOTE/BUG: the the check should be reversed:
slt $t2,$t1,$t0 # check if min is less than p
add $s3,$s3,$t0 # total += $t0
bne $t2,$zero,L3 # if min is less than p, go to L3
# NOTE/BUG: this pointer increment is out of place (i.e. it does not
# get incremented if there is a jump to L3)
# this won't affect the min value, but it will double count the value in
# the total
addi $s0,$s0,4 # p++
j L1
L2:
add $v0,$zero,$zero # return value from main = 0
jr $ra
L3:
move $s2,$t0
j L1
这里是固定版本:
.data
xyz: .word -8,16,-32,64,-128,256
msg_min: .asciiz "min: "
msg_tot: .asciiz " total: "
msg_nl: .asciiz "\n"
# int main(void)
#
# local variable register
# int *p $s0
# int *end $s1
# int min $s2
# int total $s3
#
.text
.globl main
main:
la $s0,xyz # p = foo
addi $s1,$s0,24 # end = p + 6
add $s3,$zero,$zero # total = 0
lw $s2,0($s0) # min = xyz[0]
L1:
beq $s0,$s1,L2 # if (p == end) goto L2
lw $t0,0($s0) # $t0 = *p
addi $s0,$s0,4 # p++
add $s3,$s3,$t0 # total += $t0
slt $t2,$t0,$s2 # *p < min?
bne $t2,$zero,L3 # yes, fly
j L1
L2:
li $v0,4
la $a0,msg_min
syscall
li $v0,1
move $a0,$s2 # get min value
syscall
li $v0,4
la $a0,msg_tot
syscall
li $v0,1
move $a0,$s3 # get total value
syscall
li $v0,4
la $a0,msg_nl
syscall
# exit program
li $v0,10
syscall
L3:
move $s2,$t0 # set new/better min value
j L1
这是一个稍微更简洁的版本,我颠倒了分支的意义,并且能够稍微收紧循环。此外,我将标签更改为更能描述 role/function:
.data
xyz: .word -8,16,-32,64,-128,256
msg_min: .asciiz "min: "
msg_tot: .asciiz " total: "
msg_nl: .asciiz "\n"
# int main(void)
#
# local variable register
# int *p $s0
# int *end $s1
# int min $s2
# int total $s3
#
.text
.globl main
main:
la $s0,xyz # p = foo
addi $s1,$s0,24 # end = p + 6
add $s3,$zero,$zero # total = 0
lw $s2,0($s0) # min = xyz[0]
main_loop:
beq $s0,$s1,main_done # if (p == end) goto L2
lw $t0,0($s0) # $t0 = *p
addi $s0,$s0,4 # p++
add $s3,$s3,$t0 # total += $t0
slt $t2,$s2,$t0 # *p < min?
bne $t2,$zero,main_loop # no, loop
move $s2,$t0 # set new/better min value
j main_loop
main_done:
li $v0,4
la $a0,msg_min
syscall
li $v0,1
move $a0,$s2 # get min value
syscall
li $v0,4
la $a0,msg_tot
syscall
li $v0,1
move $a0,$s3 # get total value
syscall
li $v0,4
la $a0,msg_nl
syscall
# exit program
li $v0,10
syscall
更新:
thanks that helped a lot, but
lw $t1,($s2)
doesnt work because lw will only work on pointers?
没错。请注意您是如何使用 s3
来保持 total
的。这就是代码使用 s2
来保存最小值的方式。我这样做[部分]是因为最高评论:
# int min $s2
要使用 lw
,置顶评论应该是:
# int *min $s2
要以原始方式使用 s2
,您需要如下内容:
min: .word 0
而且,您需要(在循环开始之前):
la $s2,min
而且,您必须 lw
和 sw
,这只会减慢速度。因此,除了已有的内容之外,您还需要添加一个额外的 lw
和一个额外的 sw
。
mips 有很多 寄存器[它的强项]。因此,它加快了速度,以在其中保留自动的、函数范围的变量。
但是,为了完整起见,这里有一个允许 lw
的版本。注意额外的内存访问。这很像用 -O0:
.data
min: .word 0
xyz: .word -8,16,-32,64,-128,256
msg_min: .asciiz "min: "
msg_tot: .asciiz " total: "
msg_nl: .asciiz "\n"
# int main(void)
#
# local variable register
# int *p $s0
# int *end $s1
# int *min $s2
# int total $s3
#
.text
.globl main
main:
la $s0,xyz # p = foo
addi $s1,$s0,24 # end = p + 6
add $s3,$zero,$zero # total = 0
la $s2,min # point to min
lw $t4,0($s0) # fetch xyz[0]
sw $t4,0($s2) # store in min
main_loop:
beq $s0,$s1,main_done # if (p == end) goto L2
lw $t0,0($s0) # $t0 = *p
addi $s0,$s0,4 # p++
add $s3,$s3,$t0 # total += $t0
lw $t4,0($s2) # fetch min
slt $t2,$t4,$t0 # *p < min?
bne $t2,$zero,main_loop # no, loop
sw $t0,0($s2) # store new/better min value
j main_loop
main_done:
li $v0,4
la $a0,msg_min
syscall
li $v0,1
lw $a0,0($s2) # get min value
syscall
li $v0,4
la $a0,msg_tot
syscall
li $v0,1
move $a0,$s3 # get total value
syscall
li $v0,4
la $a0,msg_nl
syscall
# exit program
li $v0,10
syscall