ARM汇编实现IEEE 754软浮点加法算法结果异常求助
ARM汇编实现IEEE 754浮点加法异常问题
测试场景:计算1.0 + 1.0,程序执行到BX lr时,预期R0寄存器值为0x40000000(对应IEEE 754单精度的2.0),但实际得到0x40800000(对应4.0)。
编译命令
arm-none-eabi-as -g -o float.o float.s arm-none-eabi-ld -o float float.o
运行与调试方式
- 用Qemu运行:
qemu-arm -g 30005 ./part5
- 远程调试:
gdb-multiarch file ./float target remote:30005
采用常规单步调试方式。
汇编代码
.section .data @ Constants exponent_mask: .word 0x7F800000 @ The two numbers we want to add num1: .word 0x3f800000 num2: .word 0x3f800000 .section .text .global main main: @ Load numbers directly LDR r0, =num1 LDR r0, [r0] LDR r1, =num2 LDR r1, [r1] @ Load constant for exponent extraction just once LDR r12, =exponent_mask LDR r12, [r12] @ Extract exponents AND r2, r0, r12 AND r3, r1, r12 LSR r2, r2, #23 LSR r3, r3, #23 @ Clear the exponent parts BIC r4, r0, r12 BIC r5, r1, r12 @ Add the implicit 1 to the fractions ORR r4, r4, #0x00800000 ORR r5, r5, #0x00800000 @ Align exponents and adjust fractions CMP r2, r3 BGT largerExponent @ r3 has larger exponent SUB r6, r3, r2 LSR r4, r4, r6 MOV r2, r3 B fractionsAligned largerExponent: SUB r6, r2, r3 LSR r5, r5, r6 fractionsAligned: ADD r4, r4, r5 @ Add aligned fractions @ Normalize if needed TST r4, #0x01000000 BEQ doneNormalize LSR r4, r4, #1 ADD r2, r2, #1 doneNormalize: @ Construct the final number LSL r2, r2, #23 ORR r0, r4, r2 BX lr
问题根源分析
问题出在分数相加后的归一化步骤:
- 1.0的IEEE 754单精度表示为
0x3F800000,指数为0x7F(偏移后的值,实际指数为0),分数部分为0;加上隐式1后,分数变为0x00800000。 - 两个数相加后
r4 = 0x00800000 + 0x00800000 = 0x01000000。 - 代码检测到该值的第24位为1,执行右移1位得到
0x00800000,同时指数加1变为0x80。 - 此时
r4仍保留了隐式1的位(0x00800000),但IEEE 754规格化数的隐式1是不存储在分数字段中的,最终构造结果时,这个位被错误地当成显式分数位,与左移后的指数位(0x80<<23 = 0x40000000)或操作,得到0x40800000。
修复方案
在归一化步骤结束后,清除分数中的隐式1位,修改后的归一化及结果构造代码如下:
@ Normalize if needed TST r4, #0x01000000 BEQ doneNormalize LSR r4, r4, #1 ADD r2, r2, #1 doneNormalize: @ 移除隐式1位,IEEE754规格化数不存储该位 BIC r4, r4, #0x00800000 @ 新增该行代码 @ Construct the final number LSL r2, r2, #23 ORR r0, r4, r2
修复后验证
修改后计算流程:
- 相加后
r4=0x01000000,归一化后r4=0x00800000,指数r2=0x80。 - 执行
BIC指令后,r4=0x00000000。 - 最终
r0 = 0x40000000 | 0x00000000 = 0x40000000,符合预期的2.0。
内容的提问来源于stack exchange,提问作者faliboiii
相关产品推荐
相关产品推荐

