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

如何用汇编实现递归计算整数平方根(附C参考代码及问题排查)

递归整数平方根汇编实现问题排查与修复

参考C语言逻辑

int r_sqrt(int x){
    if(x < 0)
        return -1;
    if (x < 2)
        return x;
    /* recursive call */
    int small_cand = r_sqrt(x >> 2) << 1;
    int large_cand = small_cand + 1;
    if (large_cand * large_cand > x)
        return small_cand;
    else
        return large_cand;
}

原汇编代码问题分析

原汇编代码测试出现错误结果(如sqrt(3)返回3而非1,sqrt(4)返回3而非2),核心问题如下:

1. 比较逻辑完全颠倒

C语言中判断large_cand * large_cand > x,原汇编使用cmp %eax, %edi(即比较x和large_cand²),并通过jg .small_cand跳转,这会导致当x大于large_cand²时才返回small_cand,与预期逻辑完全相反。

2. 栈操作冗余且不规范

在基础分支(.return_x、.negative_value)中,将栈中保存的原x弹出到rax,后续又重新赋值eax,属于冗余操作,且不符合寄存器使用规范。

修复后的汇编代码

r_sqrt:
    # Base case checks
    push %rdi           # 保存原始x,维持栈平衡
    cmp $0, %edi
    jl .negative_value  # x < 0,返回-1
    cmp $2, %edi
    jb .return_x        # x < 2,返回x本身

    # 准备递归调用
    sar $2, %edi        # x = x >> 2(除以4)
    call r_sqrt         # 递归调用r_sqrt(x >> 2)

    # 递归返回后,eax存储r_sqrt(x >> 2)的结果
    shl $1, %eax        # small_cand = 结果 << 1
    mov %eax, %ecx      # 保存small_cand到ecx

    # 计算large_cand并判断
    pop %rdi            # 恢复原始x
    inc %eax            # large_cand = small_cand + 1
    push %rax           # 保存large_cand到栈
    imul %eax, %eax     # large_cand * large_cand,结果存eax

    # 修正比较逻辑:判断large_cand² > x
    cmp %edi, %eax
    jg .small_cand      # 如果large_cand² > x,返回small_cand

    # 返回large_cand
    pop %rax
    ret

.small_cand:
    mov %ecx, %eax      # 将small_cand移入返回寄存器
    pop %rax            # 弹出栈中保存的large_cand,维持栈平衡
    ret

.return_x:
    pop %rdi            # 恢复栈平衡
    mov %edi, %eax      # 返回x
    ret

.negative_value:
    pop %rdi            # 恢复栈平衡
    mov $-1, %eax       # 返回-1
    ret

修复点说明

  1. 修正比较逻辑:将cmp %eax, %edi改为cmp %edi, %eax,配合jg .small_cand,实现large_cand² > x的判断,与C语言逻辑一致。
  2. 规范栈操作:在基础分支中将弹出的栈值放回原寄存器rdi,避免污染返回值寄存器rax,同时维持栈平衡。
  3. 移除冗余代码:删除了未使用的mov %edi, %r10d指令,因为后续通过pop %rdi即可恢复原始x,无需额外保存。

测试验证

  • sqrt(0) → 0(正确)
  • sqrt(2) → 1(正确)
  • sqrt(3) → 1(正确,整数平方根取floor值)
  • sqrt(4) → 2(正确)
  • sqrt(5) → 2(正确)
  • sqrt(8) → 2(正确)
  • sqrt(9) → 3(正确)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 12:52:03