QtSPIM下MIPS Assembly:无sqrt指令如何实现判别式开平方求整数根
QtSPIM环境下整数二次方程根计算实现
核心问题解决思路
你遇到的QtSPIM无硬件sqrt指令的问题,结合“输出整数根”的需求,完全不需要引入浮点运算逻辑:
- 整数根成立的前置条件:判别式
Δ = b² - 4ac必须为非负完全平方整数,否则不存在整数根 - 自定义整数平方根函数即可覆盖所有场景,不需要依赖硬件运算指令,逐次枚举实现对新手友好,无复杂算法要求
现有代码的显性BUG修正
对照你当前的代码,存在几个会导致程序完全无法运行的逻辑错误:
- 输入逻辑不匹配:原代码读入x1、x2作为区间值,但公式法求根的逻辑只需要二次项a、一次项b、常数项c三个参数,不需要区间输入,这也是判别式计算错误的根源之一
- 判别式计算逻辑错误:原代码中
mul $t6,$t1,0直接将4ac项置零,完全丢失常数项参与的计算,正确的判别式逻辑为Δ = b*b - 4*a*c - 分支跳转目标不匹配:判断Δ=0时跳转到
isioi标签,但实际代码中定义的等根分支标签为iso,跳转触发后会直接跑飞 - 缺失分支实现:代码中写了Δ<0时跳转到
mikro的指令,但从未定义mikro标签对应的处理逻辑 - 无效系统调用:
mega分支中写完计算逻辑直接调用syscall,但未提前设置$v0的系统调用功能号,操作完全无意义
可直接运行的完整实现
.data # 保留你原有的自定义提示字符串 msg_read_a: .asciiz"dwse arithmo a:" msg_read_b: .asciiz"dwse arithmo b:" msg_read_c: .asciiz"dwse arithmo c:" msg_root1: .asciiz"Prwto riza: " msg_root2: .asciiz"Deuteri riza: " akuro: .asciiz"h sunartish den mhdenizetai" midenizetai: .asciiz"h sunarthsh midenizetai" .text main: # 读入a值 li $v0,4 la $a0,msg_read_a syscall li $v0,5 syscall move $s0,$v0 # $s0存储二次项系数a # 读入b值 li $v0,4 la $a0,msg_read_b syscall li $v0,5 syscall move $s1,$v0 # $s1存储一次项系数b # 读入c值 li $v0,4 la $a0,msg_read_c syscall li $v0,5 syscall move $s2,$v0 # $s2存储常数项c # 计算判别式Δ = b² - 4ac mul $t0, $s1, $s1 # t0 = b² mul $t1, $s0, $s2 # t1 = a*c sll $t1, $t1, 2 # t1 = 4*a*c,用移位运算替代乘法减少指令开销 sub $t8, $t0, $t1 # t8 最终存储判别式Δ # 将Δ传入自定义整数平方根函数计算 move $a0, $t8 jal int_sqrt move $t9, $v0 # t9存储整数平方根结果 # 分支逻辑判断 blt $t8, 0, no_root # Δ<0 无实整数根 beq $t9, -1, no_root # Δ不是完全平方数,无整数根 # Δ=0场景:仅存在一个相等实根 beq $t8, 0, single_root # Δ>0场景:存在两个不同实根 # 计算x1 = (-b + sqrtΔ)/(2a) sub $t2, $zero, $s1 # t2 = -b add $t3, $t2, $t9 # t3 = -b + sqrtΔ sll $t4, $s0, 1 # t4 = 2*a div $t5, $t3, $t4 # t5 = x1 # 计算x2 = (-b - sqrtΔ)/(2a) sub $t3, $t2, $t9 # t3 = -b - sqrtΔ div $t6, $t3, $t4 # t6 = x2 # 输出两个根的结果 li $v0,4 la $a0,msg_root1 syscall li $v0,1 move $a0,$t5 syscall li $v0,4 la $a0,msg_root2 syscall li $v0,1 move $a0,$t6 syscall j exit # 单相等根处理分支 single_root: sub $t2, $zero, $s1 sll $t4, $s0, 1 div $t5, $t2, $t4 li $v0,4 la $a0,midenizetai syscall li $v0,1 move $a0,$t5 syscall j exit # 无整数根处理分支 no_root: li $v0,4 la $a0,akuro syscall j exit # 自定义整数平方根函数 # 入口参数:$a0 = 待开方的非负整数 # 返回值:$v0 = 整数平方根;输入负数或非完全平方数时返回-1 int_sqrt: bltz $a0, sqrt_neg # 输入负数直接返回-1 beq $a0, 0, sqrt_zero li $t0, 1 # 从s=1开始逐次枚举 sqrt_loop: mul $t1, $t0, $t0 # 计算当前枚举值的平方 beq $t1, $a0, sqrt_find # 匹配到完全平方数 bgt $t1, $a0, sqrt_nofind # 平方值超过待开方数仍未匹配,说明不是完全平方数 addi $t0, $t0, 1 j sqrt_loop sqrt_neg: li $v0, -1 jr $ra sqrt_zero: li $v0, 0 jr $ra sqrt_find: move $v0, $t0 jr $ra sqrt_nofind: li $v0, -1 jr $ra exit: # 程序退出 li $v0, 10 syscall
内容的提问来源于stack exchange,提问作者dabebeh66
相关产品推荐
相关产品推荐

