MIPS汇编素数判断及范围内素数输出循环实现问题
问题背景
需要实现MIPS汇编程序,功能如下:
- 接收用户输入的整数
- 判断该整数是否为素数
- 若输入为素数,同步输出所有不大于该输入值的素数
示例:输入n=11时,预期输出为:11 is prime, and so are 2, 3, 5, 7, 11
现有实现无法正确构建循环逻辑,无法完成输入值之前所有数字的素性校验,也无法正确执行输出/跳过的分支操作,原有代码如下:
.data string1: .asciiz "Please enter an integer: " string2: .asciiz "Input is a prime number" string3: .asciiz "Input is not a prime number" string4: .asciiz " " string5: .asciiz "Prime numbers up to the input are: " .text main: # Print string 1 la $a0, string1 li $v0, 4 syscall # Take input from user li $v0, 5 syscall # Store input in temp register move $t8, $v0 # Initial value for processing li $t9, 2 # Corner cases blt $t8, 1, NotPrime beq $t8, 1, NotPrime beq $t8, 2, Prime loopPrime: beq $t9, $t8, Prime # Branch to prime when input equals initial value div $t8, $t9 # Divide input by numbers in range mfhi $t1 # Move division remainder to t1 beq $t1, $0, NotPrime # If remainder equals 0, the input is not prime number addi $t9, $t9, 1 # Increment initial value by 1 b loopPrime Prime: li $v0, 4 la $a0, string2 syscall li $v0, 4 la $a0, string4 syscall li $v0, 4 la $a0, string5 syscall # Initial value2 for processing li $t7, 2 b loopfactor2 b Exit loopfactor1: addi $t7, $t7,1 b loopfactor2 loopfactor2: beq $t9, $t7, Print div $t7, $t9 mfhi $t1 beq $t1, $0, Skip addi $t9, $t9, 1 blt $t7, $t8 loopfactor1 b Exit Print: li $v0, 4 move $a0, $t7 syscall Skip: addi $t7, $t7,1 b loopfactor2 NotPrime: li $v0, 4 la $a0, string3 syscall b Exit Exit: li $v0, 10 syscall
原有代码核心错误
- 寄存器复用冲突:判断输入本身素性时
t9作为除数,值累加到和输入相等后才跳转到Prime分支,后续遍历素数时没有重置t9为2,直接复用导致除数初始值完全错误。 - 素数校验逻辑失效:遍历每个待判断数字时,没有将除数重置回初始值2,除数持续累加,导致后续所有数字的素性判断完全错误。
- 系统调用错误:打印整数需要使用
$v0=1的系统服务,原代码Print块中错误使用了打印字符串的服务号$v0=4,会触发内存访问错误或输出乱码。 - 分支逻辑混乱:
loopfactor1和loopfactor2跳转顺序颠倒,循环终止条件位置错误,会出现死循环、漏判、提前退出等问题。 - 语法错误:分支指令
blt $t7, $t8 loopfactor1缺少寄存器与标签之间的逗号,无法通过汇编器编译。 - 输出格式不匹配:预置的提示字符串与需求要求的输出格式不符,也没有处理素数之间的分隔符。
修正后可运行代码
.data prompt: .asciiz "Please enter an integer: " prime_prefix: .asciiz " is prime, and so are " not_prime_tip: .asciiz " is not a prime number" sep: .asciiz ", " .text # 素数判断函数:入参$a0=待判断数字,返回$v0=1为素数,$v0=0为非素数 is_prime: addi $sp, $sp, -8 sw $ra, 4($sp) sw $s0, 0($sp) move $s0, $a0 li $v0, 0 blt $s0, 2, is_prime_ret # 小于2的数不是素数 li $v0, 1 beq $s0, 2, is_prime_ret # 2是素数 andi $t0, $s0, 1 beqz $t0, is_prime_ret # 大于2的偶数不是素数 li $t0, 3 is_prime_loop: mult $t0, $t0 mflo $t1 bgt $t1, $s0, is_prime_ret # 除数平方大于待判断数时,是素数 div $s0, $t0 mfhi $t1 beqz $t1, is_prime_ret # 余数为0则不是素数 addi $t0, $t0, 2 # 除数步长为2,跳过偶数 b is_prime_loop is_prime_ret: lw $s0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 jr $ra main: # 打印输入提示 la $a0, prompt li $v0, 4 syscall # 读取用户输入存入$s0 li $v0, 5 syscall move $s0, $v0 # 判断输入本身是否为素数 move $a0, $s0 jal is_prime beqz $v0, print_not_prime # 输入是素数,先打印输入值 move $a0, $s0 li $v0, 1 syscall la $a0, prime_prefix li $v0, 4 syscall # 遍历2到$s0,输出所有素数 li $s1, 2 # $s1为当前遍历的数字 li $s2, 0 # $s2标记是否已输出第一个素数,用于处理分隔符 print_all_prime: bgt $s1, $s0, prog_exit move $a0, $s1 jal is_prime beqz $v0, next_iter # 当前数是素数,处理分隔符 beqz $s2, no_sep la $a0, sep li $v0, 4 syscall no_sep: li $s2, 1 move $a0, $s1 li $v0, 1 syscall next_iter: addi $s1, $s1, 1 b print_all_prime print_not_prime: move $a0, $s0 li $v0, 1 syscall la $a0, not_prime_tip li $v0, 4 syscall prog_exit: li $v0, 10 syscall
实现说明
- 将素数判断逻辑封装为独立函数,遵循MIPS栈调用约定,避免寄存器复用冲突,减少重复代码。
- 优化素数判断效率:提前排除小于2的数、2本身、偶数,后续仅用奇数做除数,且除到待判断数的平方根即可终止判断,相比原逻辑效率提升明显。
- 主流程先判断输入本身的素性,非素数直接输出对应提示;素数则从2开始遍历到输入值,逐个校验素性后输出,自动处理逗号分隔格式,第一个输出的素数前不打印逗号。
- 修正了所有语法错误、系统调用错误、分支跳转错误,输入11时可输出符合要求的结果。
内容的提问来源于stack exchange,提问作者ka177
相关产品推荐
相关产品推荐

