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

32位无符号定点二进制乘法溢出问题求助

32位定点乘法避免溢出的解决方案(PIC16汇编)

核心思路:拆分运算,避免直接计算大乘积

你的问题本质是Q2格式定点数(小数点后2位)的乘法,直接计算放大后的整数乘积会溢出32位,但可以通过拆分运算顺序,把大乘法拆分为多个小乘法+除法,所有步骤都在32位范围内完成。

以你的例子为例:

  • 888.88 对应整数 888*100 + 88 = 88888
  • 805.00 对应整数 805*100 + 0 = 80500

理论上乘积缩放后的值应为:(88888 * 80500) / 10000,直接计算分子会溢出32位,所以把式子拆分:

(88888 * 80500)/10000 = [(888*100 + 88) * (805*100)] / 10000
= (888*805*10000 + 88*805*100) / 10000
= 888*805 + (88*805*100)/10000
= 888*805 + (88*805)/100

每一步运算的结果都远小于32位最大值(4294967295):

  • 888*805 = 714840
  • 88*805 = 70840,除以100得商708,余数40(对应0.4)
  • 最终结果:714840 + 708 + 0.4 = 715548.4,完全符合需求

PIC16汇编实现步骤

  1. 拆分输入定点数

    • 将88888拆分为整数部分0x0378(十进制888)和小数部分0x58(十进制88)
    • 将80500拆分为整数部分0x0325(十进制805)和小数部分0x00(十进制0)
  2. 计算整数部分乘积
    用PIC16的MULWF指令实现16位×16位乘法(通过多次8位乘法累加):

    ; 计算888 * 805,结果存放在REG3:REG2:REG1:REG0(32位)
    MOVLW 0x78        ; 888的低8位
    MOVWF NUM1_L
    MOVLW 0x03        ; 888的高8位
    MOVWF NUM1_H
    MOVLW 0x25        ; 805的低8位
    MOVWF NUM2_L
    MOVLW 0x03        ; 805的高8位
    MOVWF NUM2_H
    
    ; 调用16位乘法子程序,结果存入PRODH:PRODL(低16位)和REG3:REG2(高16位)
    CALL MUL16x16
    

    (注:MUL16x16是自定义子程序,逻辑为分别计算高×高、高×低、低×高、低×低,再累加得到32位结果)

  3. 计算小数部分乘积并做除法
    计算88×805,然后除以100:

    ; 计算88 * 805,结果存放在PRODH:PRODL
    MOVLW 0x58        ; 88的8位值
    MOVWF NUM_F
    MOVF NUM2_L, W
    MULWF NUM_F       ; 88*25,结果在PRODH:PRODL
    MOVWF TEMP_L
    MOVF PRODH, W
    MOVWF TEMP_H
    MOVF NUM2_H, W
    MULWF NUM_F       ; 88*3,结果在PRODH:PRODL
    ; 累加:88*(3*256 +25) =88*805
    MOVF PRODL, W
    ADDWF TEMP_L, F
    MOVF PRODH, W
    ADDWFC TEMP_H, F
    
    ; 调用16位除以8位的除法子程序,TEMP_H:TEMP_L / 100,商存于QUOT,余数存于REM
    MOVLW 0x64        ; 100的十六进制是0x64
    MOVWF DIVISOR
    CALL DIV16x8
    

    (注:DIV16x8子程序可采用循环减法实现,或分解除法:先右移2位除以4,再用减法除以25,提升效率)

  4. 合并结果
    将整数乘积的结果加上除法的商,余数对应小数点后的值:

    ; 把整数乘积的低16位(REG1:REG0)加上QUOT
    MOVF QUOT, W
    ADDWF REG0, F
    MOVLW 0x00
    ADDWFC REG1, F
    ; 最终整数部分是REG3:REG2:REG1:REG0(十进制715548),余数REM=40对应0.4
    

通用扩展(适用于两个数都有小数的情况)

如果两个数都是Q2格式(比如a=A*100+a_frac,b=B*100+b_frac),可沿用同样拆分逻辑:

(a*b)/10000 = AB + (A*b_frac + B*a_frac)/100 + (a_frac*b_frac)/10000

每一项运算都不会溢出32位,最后合并整数部分和小数部分即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 07:52:28