MIPS程序集中的二进制搜索无法正常工作

时间:2014-12-20 17:30:57

标签: assembly mips binary-search

我想在数据段中搜索一个数字并打印出保存的位置。它适用于除1和10000之外的所有数字,但我不知道为什么,它也打印出错误的“位置”......

以下是代码:

### Binary search ############################################################
.text
binsearch:
##############################################################################
# $a0 - Number n
# $a1 - Lower bound lo
# $a2 - Upper bound hi
# $v0 - Position where n is found, -1 if not found
##############################################################################

addi $sp, $sp, -4
sw $ra, 0($sp)
bge $a1, $a2, binsearch_not_found

sub $t0, $a2, $a1
srl $t0, $t0, 2
add $t1, $a1, $t0
sll $t2, $t1, 2
lw $t3, list($t2)
beq $t3, $a0, binsearch_found
blt $t3, $a0, binsearch_upper_half

binsearch_lower_half:
#####################
subi $a2, $t1, 1
jal binsearch
j binsearch_return

binsearch_upper_half:
#####################
addi $a1, $t1, 1
jal binsearch
j binsearch_return

binsearch_found:
################
move $v0, $t2
j binsearch_return

binsearch_not_found:
####################
li $v0, -1

binsearch_return:
#################
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra

### Main #####################################################################
.globl main
main:
##############################################################################

li $v0, 4
la $a0, input
syscall

li $v0, 5
syscall
move $a0, $v0

move $a1, $zero
lw $a2, length
subi $a2, $a2, 1
jal binsearch

li $t0, -1
beq $v0, $t0, not_found

found:
######
mul $t0, $v0, 4
lw $a0, list($t0)
li $v0, 1
syscall

li $v0, 4
la $a0, success
syscall
j repeat

not_found:
##########
li $v0, 4
la $a0, failure
syscall

repeat:
#######
li $v0, 4
la $a0, continue
syscall

# Read characters
li $v0, 12
syscall
move $t0, $v0

li $v0, 4
la $a0, newline
syscall

# End when 'y'
bne $t0, 'y', main

li $v0, 10
syscall

### Data #####################################################################
.data
##############################################################################

input:    .asciiz "Which number? "
continue: .asciiz "Abort? (y/n) "
failure:  .asciiz "Not found\n"
success:  .asciiz " found\n"
newline:  .asciiz "\n"

length:   .word 100
list:     .word    1,    4,    9,   16,   25,   36,   49,   64,   81,   100,
          .word  121,  144,  169,  196,  225,  256,  289,  324,  361,   400,
          .word  441,  484,  529,  576,  625,  676,  729,  784,  841,   900,
          .word  961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521,  1600,
          .word 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401,  2500,
          .word 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481,  3600,
          .word 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761,  4900,
          .word 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241,  6400,
          .word 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921,  8100,
          .word 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801, 10000

1 个答案:

答案 0 :(得分:0)

发现错误

  1. 第13行:bge $a1, $a2, binsearch_not_found
    应该有bgt,因为在$a1 == $a2时,已找到号码$a0。如果您想将$a2解释为严格的上限,则subi $a2, $a2, 1binsearch之前main的调用是奇数。

  2. 第16行:srl $t0, $t0, 2
    应该有1而不是2。您希望将$t0除以2而不是4。

  3. 第37行:move $v0, $t2
    应该有$t1而不是$t2binsearch应该将索引返回到数组中,而不是以字节为单位进行偏移。如果您想要返回偏移量,则不应将binsearch的返回值乘以main第73行(mul $t0, $v0, 4)。

  4. 其他观察和想法

    • 还有另一种方法可以计算当前检查间隔中间的索引。您可以使用mid = (hi - lo) / 2 + lo代替mid = (hi + lo) / 2。这样可以保存指令并且溢出不是您的问题。

    • 您使用的寄存器数多于binsearch中所需的寄存器数。我设法只使用$t0作为索引,$t1作为list的偏移量,然后使用该偏移量的值。但是,不知道这会如何影响性能。 (请注意,更改此操作非常容易出错。请务必考虑使用寄存器值的位置并同时更改所有引用。)

    • 您只打印找到的号码。打印索引可能会有所帮助。

    MARS

    为了调试你的代码,我使用了MIPS的MARS模拟器(来自密苏里州立大学,nice description在Gary Shute的网站上,明尼苏达大学德卢斯分校)。我需要在j main标签之前添加binsearch,否则执行binsearch而不是main,这很快就会导致崩溃。

    我在MARS中关闭delayed branching,否则必须在跳转和分支后添加nop指令,以便不执行不应执行的操作。我被告知MIPS有一个延迟槽,但你似乎没有考虑到它。我认为,因为你可能知道你的架构是否有延迟槽,而且我不是汇编编程专业人员,也不知道延迟槽编程的复杂性。