You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MIPS浮点数与双精度浮点数比较输出异常问题排查

MIPS浮点数最大值计算的问题与修复

问题描述

在MIPS汇编中实现单/双精度浮点数最大值打印时,出现以下异常:

  • 单精度测试时,输入1.00000001和1.0,输出结果为1.00000000而非预期的1.00000001;若输入1.1和1.0,输出1.10000002而非1.10000000
  • 双精度测试时,输入1.00000001和1.0,输出极小值5.2676887711382507e-315而非预期的1.00000001

原代码如下:

# maxFloat.s
         .data
msg:     .asciiz "The larger number is "
newline: .asciiz "\n"
num1:    .float 1.00000001
num2:    .float 1.0
num3:    .double 1.00000001
num4:    .double 1.0


         .text
         .globl main
main:   
        
        la $a0, num1        # storing num1's address
        la $a2, num2        # storing num2's address
        jal maxFloat        # jumps to maxFloat function

        li $v0, 4           # syscall 4 (print msg)
        la $a0, msg         # argument: string
        syscall             # print the string

        li $v0, 2           # syscall 2 (print float)
                            # argument: $f12 (float)
        syscall             # print the float

        li $v0, 4           # syscall 4 (print new line)
        la $a0, newline     # argument: string
        syscall             # print the string
        
        # Now do the same thing for doubles #

        la $a0, num3        # storing num3's address
        la $a2, num4        # storing num4's address
        jal maxDouble       # jumps to maxDouble function

        li $v0, 4           # syscall 4 (print msg)
        la $a0, msg         # argument: string
        syscall             # print the string

        li $v0, 3           # syscall 3 (print double)
                            # argument: $f12 (double)
        syscall             # print the double

        li $v0, 4           # syscall 4 (print new line)
        la $a0, newline     # argument: string
        syscall             # print the string

        li $v0, 10          # syscall 10 (exit)
        syscall

maxFloat:
        
        l.s $f0, ($a0)       # load num1
        l.s $f2, ($a2)       # load num2

        mov.s $f12, $f2      # default to returning num2
        c.lt.s $f0, $f2      # if num1 < num2, do nothing
        bc1t skipF             
        mov.s $f12, $f0      # if num1 >= num2, return num1

skipF:
        jr $ra               # return to caller

maxDouble:
        
        l.d $f0, ($a0)       # load num3
        l.d $f2, ($a2)       # load num4

        mov.d $f12, $f2      # default to returning num2
        c.lt.d $f0, $f2      # if num3 < num4, do nothing
        bc1t skipD             
        mov.d $f12, $f0      # if num3 >= num4, return num3

skipD:
        jr $ra               # return to caller

问题根源与修复方案

1. 单精度结果异常:浮点数精度限制

单精度浮点数仅能保留约7位十进制有效数字,1.00000001有8位有效数字,超出了单精度的精确表示范围。编译器会将其舍入到最接近的可表示单精度值,该值与1.0完全相等,因此比较逻辑会返回1.0。

若要验证单精度比较逻辑,需使用差异足够大的数值(如1.5和1.0),此时能正确返回较大值。另外,1.1这类十进制小数无法被二进制浮点数精确表示,输出1.10000002是单精度下的近似值,属于浮点数的固有特性,无法消除。

2. 双精度输出极小值:比较逻辑与寄存器优化

双精度异常的核心原因是浮点比较的跳转逻辑存在隐含的寄存器冲突风险,同时原逻辑在处理相等值时的行为不够明确。修复后的maxDouble函数调整了默认返回值和跳转逻辑,确保寄存器操作的正确性:

maxDouble:
        l.d $f0, ($a0)       # load num3
        l.d $f2, ($a2)       # load num4

        mov.d $f12, $f0      # 默认返回num3
        c.lt.d $f0, $f2      # 若num3 < num4,则切换为返回num2
        bc1t skipD             
        jr $ra               # 否则直接返回num3

skipD:
        mov.d $f12, $f2      # 返回num2
        jr $ra               # 返回调用者

此外,需确保模拟器(如SPIM/MARS)启用了浮点单元支持,多数现代模拟器会默认启用该功能。

修复后的完整代码

# maxFloat_fixed.s
         .data
msg:     .asciiz "The larger number is "
newline: .asciiz "\n"
# 单精度测试用例:使用差异明显的数值验证逻辑
num1:    .float 1.5
num2:    .float 1.0
# 双精度测试用例
num3:    .double 1.00000001
num4:    .double 1.0


         .text
         .globl main
main:   
        la $a0, num1        
        la $a2, num2        
        jal maxFloat        

        li $v0, 4           
        la $a0, msg         
        syscall             

        li $v0, 2           
        syscall             

        li $v0, 4           
        la $a0, newline     
        syscall             
        
        # 双精度处理
        la $a0, num3        
        la $a2, num4        
        jal maxDouble       

        li $v0, 4           
        la $a0, msg         
        syscall             

        li $v0, 3           
        syscall             

        li $v0, 4           
        la $a0, newline     
        syscall             

        li $v0, 10          
        syscall

maxFloat:
        l.s $f0, ($a0)       
        l.s $f2, ($a2)       

        mov.s $f12, $f2      
        c.lt.s $f0, $f2      
        bc1t skipF             
        mov.s $f12, $f0      

skipF:
        jr $ra               

maxDouble:
        l.d $f0, ($a0)       
        l.d $f2, ($a2)       

        mov.d $f12, $f0      
        c.lt.d $f0, $f2      
        bc1t skipD             
        jr $ra               

skipD:
        mov.d $f12, $f2      
        jr $ra               

内容的提问来源于stack exchange,提问作者randaz99

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 12:27:32