x87汇编实现1-(x/y)的零值处理与范围钳位求助
x87汇编:实现
1 - (x/y)的边界处理方案 需求说明
公式:1 - (x/y)
背景:X、Y均为正浮点数,但计算结果可正可负,该计算是某个最终结果为正数的更大计算流程的一部分。
待解决的两个问题
- 问题1:X或Y可能为零(也可能同时为零),必须避免除零错误。只要任一值为零,最终结果直接设为1(执行
Fld1,弹出多余数值后继续后续计算)。 - 问题2:计算结果必须限制在[-1, 1]区间内。若结果大于1或小于-1,直接替换为1。例如
1 - (35/0.01)这种情况,结果会远小于-1,需要替换为1。
已有代码片段
fld dword [y] ; Check if either number is 0 fmul dword [x] ; Fldz fcomip st(1),st(0) je exit_1 ; If result is zero jump outta here fld dword [y] ; Otherwise load the floats fld dword [x] fdivp ; Do X/Y fld1 fsubrp ; 1 - X/Y ????? ; Need some code here to check result is between -1 and 1. If not, replace the result with "1" every time. .exit_1 fld1 ; Use 1 as the result for the next calculation jump to_next_calc
解决思路与代码补充
问题1的现有逻辑优化
现有通过x*y是否为零判断x或y是否为零的逻辑可行,但fcomip执行后会弹出栈顶的0值,此时栈中剩余x*y的结果。需要在跳转前弹出该值保证栈平衡,否则后续操作会出错。
问题2的区间判断实现
计算出1 - x/y的结果后(值在st(0)),需要分两步和边界值比较:
- 和1比较:若结果大于1,跳转替换为1;
- 和-1比较:若结果小于-1,跳转替换为1;
- 若都不触发跳转,说明结果在[-1,1]区间内,直接保留。
补充后的完整代码:
; 检查x或y是否为零 fld dword [y] fmul dword [x] fldz fcomip st(1), st(0) ; 比较x*y与0,同时弹出栈顶的0 fstp st(0) ; 弹出x*y的结果,平衡栈 je exit_1 ; 若x或y为零,跳转到结果设为1的分支 ; 计算1 - x/y fld dword [y] fld dword [x] fdivp ; st(0) = x/y,弹出x fld1 fsubrp ; st(0) = 1 - x/y,弹出1 ; 检查结果是否大于1 fld1 fcomip st(1), st(0) ; 比较原结果与1,弹出栈顶的1 ja replace_with_1 ; 原结果>1时跳转 ; 检查结果是否小于-1 fld1 fchs ; 将1转为-1,替代直接加载常量的方式 fcomip st(1), st(0) ; 比较原结果与-1,弹出栈顶的-1 jb replace_with_1 ; 原结果<-1时跳转 ; 结果符合区间要求,直接进入后续计算 jmp to_next_calc replace_with_1: fstp st(0) ; 弹出不符合要求的原结果 fld1 ; 替换为1 jmp to_next_calc .exit_1 fld1 ; 用1作为结果进入后续计算 jmp to_next_calc
关键注意点
- 用
fld1+fchs生成-1,避免额外定义常量的麻烦; - 每次
fcomip都会自动弹出栈顶的比较值,需注意栈内剩余元素的处理,始终保持栈平衡。
内容的提问来源于stack exchange,提问作者X87-Learner
相关产品推荐
相关产品推荐

