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

Cortex M0+/GCC 带舍入的整数除法实现方案问询

无除法指令Cortex-G0内核的带舍入整数除法优化实现

核心优化思路:复用除法过程的余数,避免额外计算

Cortex-G0没有硬件除法指令,编译器会生成基于减法移位的软件除法子程序——这类实现大多会在计算商的同时算出余数(比如ARM GCC的__divsi3/__modsi3本质是同一个子程序,执行一次就能拿到商和余数)。你完全不需要单独计算余数,只要复用这个过程的结果就能实现舍入,避免重复开销。

通用舍入逻辑(四舍五入)

针对任意正负的被除数a和除数b,可以用以下代码实现,尽量用低开销的位运算代替乘法/绝对值:

int rounded_div(int a, int b) {
    int q = a / b;
    int r = a - q * b; // 用减法算余数,比直接调用%更省周期(若编译器未优化)
    
    // 判断是否需要进位:余数的2倍绝对值 >= 除数绝对值,且符号匹配时进位
    if ((r << 1) >= b && r > 0) {
        q++;
    } else if ((r << 1) <= b && r < 0) {
        q++;
    }
    return q;
}

如果是向正无穷取整(而非四舍五入),逻辑更简单:当余数非零且被除数与除数同号时,商加1,开销更低:

int ceil_div(int a, int b) {
    int q = a / b;
    int r = a - q * b;
    if (r != 0 && ((a > 0 && b > 0) || (a < 0 && b < 0))) {
        q++;
    }
    return q;
}

关于反汇编分析:必须做

不同编译器(GCC/ARMCC)生成的软件除法实现差异很大,有些会把商和余数存在寄存器里返回,有些可能会重复调用除法子程序。看反汇编能帮你确认:

  • 编译器是否在一次除法计算后同时输出商和余数
  • 余数的存储位置,是否可以直接复用,避免额外指令

比如ARM GCC开启-O2优化后,同时使用a/b和a%b会被优化为一次子程序调用,同时获取两个值;如果没优化,你可能需要手动调整代码或内联汇编。

是否需要自行编写汇编?

  • 若编译器优化到位(开启-O2/-O3),不需要——复用商和余数的代码已经足够高效。
  • 若追求极致低开销,建议写——把舍入逻辑直接嵌入除法循环,避免后续分支判断的额外周期。

以下是一个简化的Thumb-2汇编实现(32位整数,四舍五入):

; 输入:R0 = 被除数a, R1 = 除数b
; 输出:R0 = 带舍入的商
rounded_div:
    PUSH {R4-R6, LR}
    EOR R4, R0, R1       ; 计算符号位(异或结果为负则商为负)
    ; 取被除数和除数的绝对值
    MOV R5, R0
    CMP R0, #0
    IT LT
    NEG R5, R0
    MOV R6, R1
    CMP R1, #0
    IT LT
    NEG R6, R1
    ; 初始化商和余数
    MOV R0, #0
    MOV R1, R5
    ; 除法循环(移位减法)
    MOVS R2, #32
div_loop:
    LSL R1, R1, #1
    LSL R0, R0, #1
    CMP R1, R6
    IT HS
    SUBS R1, R1, R6
    IT HS
    ADD R0, R0, #1
    SUBS R2, R2, #1
    BNE div_loop
    ; 判断是否舍入:2*余数 >= 除数?
    LSL R1, R1, #1
    CMP R1, R6
    IT HS
    ADD R0, R0, #1
    ; 恢复商的符号
    CMP R4, #0
    IT LT
    NEG R0, R0
    POP {R4-R6, PC}

这个实现把舍入判断直接放在除法循环结束后,没有额外函数调用,周期开销极小。

公认的优化方案

针对无硬件除法的ARM内核,业界公认的低开销方案:

  • 复用除法子程序的余数:同时使用/和%,开启编译器优化,确保只执行一次除法计算。
  • 替换高开销操作:用移位代替乘法,用符号判断代替abs函数,减少指令数。
  • 嵌入舍入逻辑:极致优化时,修改除法汇编,将舍入判断整合到除法过程中,避免后续分支。
  • 场景特化:如果除数是2的幂,用移位+简单判断实现,但你这里除数是任意整数,此方法不适用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 10:17:23