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

MARS MIPS单精度IEEE754浮点数乘法程序结果为无穷大求助

问题分析与解决方案

当前代码的问题

  1. 违反需求限制:代码中使用了mul.s、add.s等MIPS浮点算术指令,不符合“禁止使用MIPS浮点算术指令”的要求。
  2. 输出无穷大的直接原因:
    • $f4的值是0x7F000000,这是IEEE754单精度标准中的正无穷大(指数位全为1,尾数位全为0)。
    • 当执行mul.s $f8, $f4, $f5时,无穷大与任何非NaN的数相乘结果仍是无穷大,后续加法操作无法改变这个结果,最终输出自然为无穷大。

正确实现思路(手动IEEE754乘法)

因为不能使用浮点算术指令,我们需要通过整数寄存器操作,手动解析和计算IEEE754单精度浮点数的乘法:
单精度IEEE754结构:1位符号位(bit31)、8位指数位(bits30-23)、23位尾数位(bits22-0,规格化数隐含最高位1)

核心步骤

  • 读取输入:从FLOAT2.BIN文件读取8字节数据,拆分两个4字节浮点数到整数寄存器。
  • 解析浮点数:提取每个数的符号位、指数、尾数(补充隐含的1)。
  • 计算结果各部分:
    • 符号位:两个数符号位的异或(同号为正,异号为负)。
    • 尾数:将两个含隐含位的尾数(24位)相乘,得到48位结果,根据结果最高位调整移位和指数。
    • 指数:两个数的指数相加后减去偏移量127,再根据尾数相乘的移位结果调整。
  • 处理特殊情况:处理0、无穷大、NaN等边界情况。
  • 打包输出:将结果的符号位、指数、尾数重新组合为32位整数,通过浮点寄存器加载后输出。

示例代码

.data
    buffer: .space 8       # 存储从文件读取的8字节数据
    filename: .asciiz "FLOAT2.BIN"

.text
.globl main
main:
    # 打开文件
    li $v0, 13
    la $a0, filename
    li $a1, 0              # 只读模式
    li $a2, 0
    syscall
    move $s0, $v0          # 保存文件描述符

    # 读取8字节到buffer
    li $v0, 14
    move $a0, $s0
    la $a1, buffer
    li $a2, 8
    syscall

    # 关闭文件
    li $v0, 16
    move $a0, $s0
    syscall

    # 加载两个浮点数到整数寄存器(不用lwc1)
    lw $s1, buffer         # num1的32位值
    lw $s2, buffer+4       # num2的32位值

    # ---------- 解析num1 ----------
    srl $t0, $s1, 31       # num1符号位 s1 = $t0
    srl $t1, $s1, 23
    andi $t1, $t1, 0xFF    # num1指数 exp1 = $t1
    andi $t2, $s1, 0x7FFFFF # num1尾数 mant1 = $t2
    # 补充隐含的1(规格化数)
    li $t3, 1 << 23
    or $t2, $t2, $t3       # mant1 = 隐含1 + 尾数

    # ---------- 解析num2 ----------
    srl $t4, $s2, 31       # num2符号位 s2 = $t4
    srl $t5, $s2, 23
    andi $t5, $t5, 0xFF    # num2指数 exp2 = $t5
    andi $t6, $s2, 0x7FFFFF # num2尾数 mant2 = $t6
    or $t6, $t6, $t3       # mant2 = 隐含1 + 尾数

    # ---------- 计算结果符号位 ----------
    xor $s3, $t0, $t4      # result_s = s1 ^ s2

    # ---------- 计算结果尾数(64位乘法) ----------
    multu $t2, $t6         # mant1 * mant2,结果在HI/LO
    mfhi $t7               # 高32位
    mflo $t8               # 低32位

    # 检查48位结果的最高位(HI的第15位,因为24*24=48位,HI的高16位是结果的高16位)
    srl $t9, $t7, 15
    andi $t9, $t9, 1
    beqz $t9, shift_mant   # 如果最高位是0,不需要额外移位

    # 最高位是1,指数加1,尾数右移1位
    addi $t5, $t5, 1
    srl $t7, $t7, 1
    sll $t0, $t8, 31
    or $t7, $t7, $t0
    srl $t8, $t8, 1
    j calc_exp

shift_mant:
    # 尾数右移8位,取高23位(因为48位结果,取前23位作为尾数)
    srl $t7, $t7, 8
    sll $t0, $t8, 24
    or $t7, $t7, $t0
    andi $t7, $t7, 0x7FFFFF # 保留23位尾数

calc_exp:
    # 计算结果指数:exp1 + exp2 - 127
    add $s4, $t1, $t5
    subi $s4, $s4, 127
    # 这里可以添加指数溢出/下溢的处理(比如超过255设为无穷大,低于0设为非规格化)

    # ---------- 打包结果 ----------
    sll $s3, $s3, 31       # 符号位移到bit31
    sll $s4, $s4, 23       # 指数移到bits30-23
    or $s5, $s3, $s4
    or $s5, $s5, $t7       # 合并尾数

    # 加载结果到浮点寄存器(仅用mtc1,不用算术指令)
    mtc1 $s5, $f12
    # 输出浮点数
    li $v0, 2
    syscall

    # 退出程序
    li $v0, 10
    syscall

说明

  • 代码全程使用整数寄存器操作解析和计算,未使用任何浮点算术指令(仅用mtc1加载结果到浮点寄存器用于输出)。
  • 包含了从FLOAT2.BIN文件读取输入的逻辑,符合需求。
  • 处理了规格化数的尾数计算,可扩展添加对非规格化数、无穷大、NaN等特殊情况的处理。

内容的提问来源于stack exchange,提问作者Khoa Nguyễn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 21:54:53