MARS MIPS单精度IEEE754浮点数乘法程序结果为无穷大求助
问题分析与解决方案
当前代码的问题
- 违反需求限制:代码中使用了
mul.s、add.s等MIPS浮点算术指令,不符合“禁止使用MIPS浮点算术指令”的要求。 - 输出无穷大的直接原因:
$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
相关产品推荐
相关产品推荐

