FCOMIP指令相关NASM双精度数比较代码结果不一致求助
我一眼就看到问题出在跳转指令的选择上——你用了整数指令jge来处理浮点数比较的结果,但fcomip对EFLAGS的设置方式和整数指令预期的完全不匹配,导致跳转逻辑几乎总是出错。
具体来说,fcomip只会修改EFLAGS的CF、PF、ZF位,同时把SF和OF清零。而jge(有符号整数的“大于等于”跳转)的条件是(SF == OF) || ZF。由于SF和OF都是0,SF == OF永远为真,所以不管你的两个浮点数实际大小如何,jge几乎都会跳转到minmax1_next分支,也就是总是选择a作为最小值——只有当a本身就是较小值的时候结果才正确,一旦b更小,结果就错了,这正好符合你说的“有时正确有时不正确”的现象。
给你几个修复方案,按推荐程度排序:
方案1:用SSE指令直接取最小值(最简洁可靠)
如果你的CPU支持SSE2(现在几乎所有x86 CPU都支持),直接用专门的minsd指令就行,完全不需要折腾x87栈和标志位:
movsd xmm0, qword [a] ; 把a加载到xmm0 minsd xmm0, qword [b] ; xmm0 = min(a, b) movsd qword [minval], xmm0 ; 把结果存到minval
方案2:修正跳转指令,用jae代替jge
如果你坚持用x87的写法,把jge换成jae就可以。jae是无符号的“大于等于”跳转,它的条件是CF == 0,正好匹配fcomip的结果:当b >= a时,CF会被设为0,此时jae跳转去选a;当b < a时,CF为1,不跳转,选b。修正后的代码:
fld qword[a] fld qword[b] fcomip ; 比较ST0(b)和ST1(a),弹出ST0 fstp qword [float_temp_var] ; 清空x87栈 jae minmax1_next ; b >= a时跳转 movsd xmm0,[b] movsd [minval],xmm0 jmp minmax1_out minmax1_next: movsd xmm0,[a] movsd [minval],xmm0 minmax1_out:
方案3:用x87的条件移动指令(避免跳转)
另一种x87写法是用fcmovb条件移动指令,不需要跳转,代码更流畅:
fld qword [a] fld qword [b] fcomi st0, st1 ; 比较ST0(b)和ST1(a),不弹出栈 fcmovb st0, st1 ; 如果b < a,把ST1(a)复制到ST0,此时ST0是较小值 fstp qword [minval] ; 把最小值存入minval,弹出栈顶 fstp qword [float_temp_var] ; 清空x87栈剩余内容
另外提醒一句:混合x87和SSE指令本身没问题,但如果能用SSE就尽量用,x87的栈操作很容易出错,像你这次的问题就是典型的标志位理解错误导致的。
内容的提问来源于stack exchange,提问作者RTC222
相关产品推荐
相关产品推荐

