MIPS嵌套循环质数求解代码冻结故障排查求助
Hey there! Let's break down why your MIPS prime-finding code is freezing and fix those loop issues you're suspicious of—this is super common when getting started with MIPS assembly, so don't stress.
First: The Dead Loop That's Freezing Your Program
The biggest issue is your inner loop (L1) has no way to progress! Look at your code: once you enter L1, you never increment $t2 (the divisor you're checking). That means $t2 stays at whatever initial value you set it to (I assume $t6 is 2), and as long as that value is less than $t1, the blt $t2, $t1 L1 condition will always be true. Your program gets stuck spinning in this loop forever, hence the freeze.
You need to add an increment for $t2 inside the inner loop—right after your branch check at label I is perfect:
I: addi $t2, $t2, 1 # Increment divisor by 1 each loop iteration blt $t2, $t1 L1
Second: Prime-Checking Logic Gaps
Even once you fix the dead loop, your logic has a couple of tweaks to make it work correctly and efficiently:
- Exit early when a divisor is found: Right now, if you find a number that divides
$t1(i.e.,remureturns 0), you set$t3but keep looping. There's no need to check further—if one divisor exists, the number isn't prime. Add a jump to exit the inner loop immediately after marking the non-prime flag:
Don't forget to add anbne $t4, $zero, I move $t3, $t5 # Mark as non-prime j END_L1 # Jump out of inner loop right away I: addi $t2, $t2, 1END_L1label after the inner loop to jump to. - Optimize the inner loop range: You don't need to check all the way up to
$t1—checking up to$t1/2(or even the square root of$t1) is enough. If a numbernhas a factor larger thann/2, the only possible factor isnitself (which we don't care about for primes). This cuts your loop iterations in half, making the program way faster. - Don't forget to increment
$t1!: Looking at your outer loop, you never increment the number you're checking ($t1). That means you'll keep checking the same number forever, even after fixing the inner loop. Add an increment at the end of the outer loop before jumping back toL2:P: addi $t1, $t1, 1 # Move to the next number to check bgt $t1, $t0, E j L2
Fixed Code Snippet (Key Changes Highlighted)
Here's how your core loop should look with all these fixes:
#Outer loop L2: move $t3, $zero # Reset non-prime flag to 0 move $t2, $t6 # Initialize divisor to 2 (ensure $t6 = 2!) # Calculate $t1/2 for optimized loop condition add $t7, $t1, $zero srl $t7, $t7, 1 # $t7 = $t1 divided by 2 (bit shift is faster than div) # Inner loop L1: remu $t4, $t1, $t2 bne $t4, $zero, I move $t3, $t5 # Mark as non-prime j END_L1 # Exit inner loop early once divisor is found I: addi $t2, $t2, 1 # ⚠️ Critical: Increment divisor to avoid dead loop blt $t2, $t7, L1 # Loop only up to $t1/2 (optimized condition) END_L1: bne $t3, $zero, P # Print the prime number li $v0, 1 move $a0, $t1 syscall li $v0, 4 la $a0, space syscall P: addi $t1, $t1, 1 # ⚠️ Critical: Move to next number to check bgt $t1, $t0, E j L2 E: li $v0, 10 syscall # call operating sys end: jr $ra
Just double-check that your initial values are set correctly before entering L2: $t1 should start at 2 (the first prime), $t0 should be the upper limit of numbers you want to check, $t5 should be set to 1 (to mark non-primes), and $t6 should be 2 (the starting divisor).
内容的提问来源于stack exchange,提问作者shadowGamerz

