如何仅用算术运算和逻辑门在ASM中筛选两数大小并存入指定变量
无分支实现两数大小排序的汇编方案
核心思路
利用算术运算+符号位掩码实现无分支的大小判断,全程不需要jmp类分支指令。核心逻辑是通过两数差值的符号位生成全1/全0掩码,再用掩码选择对应数值存入big和small。
代码实现(x86 32位 NASM 语法)
section .data num1 dd 150 ; 输入变量1 num2 dd 80 ; 输入变量2 big dd ? ; 存储较大值 small dd ? ; 存储较小值 section .text global _start _start: ; 生成差值符号掩码 mov eax, [num1] sub eax, [num2] ; eax = num1 - num2 cdq ; 符号位扩展到edx:差值为负则edx=0xFFFFFFFF,否则edx=0x00000000 ; 计算big mov ebx, [num1] mov ecx, [num2] sub ecx, ebx ; ecx = num2 - num1 and ecx, edx ; 仅当num1 < num2时,保留num2-num1;否则为0 add ebx, ecx ; num1小则加num2-num1得到num2,否则保持num1 mov [big], ebx ; 计算small(两种方式选其一即可) ; 方式1:用总和减big(最简洁) mov eax, [num1] add eax, [num2] sub eax, [big] mov [small], eax ; 方式2:复用掩码逻辑(和big对称) ; mov ebx, [num2] ; mov ecx, [num1] ; sub ecx, ebx ; ecx = num1 - num2 ; and ecx, edx ; 仅当num1 < num2时,保留num1-num2;否则为0 ; add ebx, ecx ; num2大则加num1-num2得到num1,否则保持num2 ; mov [small], ebx ; Linux环境退出程序 mov eax, 1 xor ebx, ebx int 0x80
关键指令说明
cdq:将EAX的符号位扩展到EDX,自动生成我们需要的掩码。这是实现无分支判断的核心,避免了jge/jl等分支指令。- 掩码运算:
and ecx, edx利用掩码筛选有效差值,只有当num1更小时,差值才会被保留并参与后续加法,最终得到较大值。
关于和差平均法的问题
你尝试的(num1+num2+abs(num1-num2))/2方案,容易出现整数溢出:当num1和num2都是较大的正数时,两数之和会超出寄存器范围,导致计算结果错误。而掩码法不存在这个问题,只要两数的差值在寄存器范围内即可正常工作。
内容的提问来源于stack exchange,提问作者Harel
相关产品推荐
相关产品推荐

