如何在RARS中正确实现无符号32位整数乘法?
正确实现RISC-V无符号64位整数乘法的方法
首先,咱们先梳理下你代码里的核心问题:数字处理的逻辑顺序反了,而且对mulhu的使用场景和64位值的乘法拆分理解有误。
问题分析
你当前的代码是先把新数字加到s3(低32位),再乘以10,这不符合“逐位构建整数”的逻辑——正确的逻辑应该是先把当前的64位值乘以10,再加上新的数字。另外,mulhu是用来获取无符号32×32乘法的高32位结果,但你只单独调用它却没有把结果合并到高32位寄存器s4里,这就导致高32位一直是0,看起来s3也没正确更新。
另外要记住:RISC-V中,mul指令的低32位结果对于有符号和无符号乘法是完全相同的,区别只在高32位(mulh对应有符号,mulhu对应无符号)。所以处理无符号64位值的乘法时,需要同时计算低32位的乘积和高32位的进位/乘积。
修正后的代码实现
下面是修正后的biggerthan0段逻辑,专门处理无符号64位值的×10 + 新数字操作:
biggerthan0: addi t0, t0, 1 # 移动到下一个字符 sub t2, t2, t4 # 将ASCII字符转为数字(0-9) # 第一步:将当前64位值(s4:s3)乘以10 mul s3, s3, s2 # 计算低32位×10,结果存在s3(无符号和有符号低32位结果一致) mulhu t6, s3, s2 # 计算低32位×10的高32位部分 mul t7, s4, s2 # 计算高32位×10的低32位部分 add s4, s4, t6 # 把低32位乘法的高32位加到高32位寄存器 add s4, s4, t7 # 加上高32位乘法的低32位,得到完整的高32位结果 # 第二步:加上新的数字t2 add s3, s3, t2 # 先加到低32位 bltu s3, t2, carry # 无符号加法溢出判断:若加前的s3 < t2,说明加完后溢出 j digit carry: addi s4, s4, 1 # 高32位加1处理进位 j digit
关键细节解释
- 64位值的乘法拆分:当你要把64位值
(s4 << 32 | s3)乘以10时,需要拆分计算:- 低32位
s3×10,低32位结果留在s3,高32位部分加到s4 - 高32位
s4×10,低32位结果加到s4(由于10数值较小,这部分的高32位不会产生溢出)
- 低32位
- 无符号加法的溢出判断:无符号数加法中,若
a + b溢出,等价于a < (2^32 - b),所以用bltu s3, t2, carry来判断加完新数字后是否需要向高32位进位。 mulhu的正确用法:mulhu rd, rs1, rs2会计算rs1 × rs2的无符号高32位,必须将这个结果合并到高32位寄存器s4,才能完整更新64位值的高半部分。
额外优化建议
- 你定义的
s5 = 429496729是(2^32-1)/10,这个值原本是用来判断乘法是否会溢出,但在修正后的逻辑里,我们通过拆分乘法和单独处理进位,已经不需要这个判断了,可以移除。 - 记得在最终输出64位结果时,要同时打印
s4(高32位)和s3(低32位),确保完整输出64位无符号数。
内容的提问来源于stack exchange,提问作者Sotaro Suzuki




