x87能否对无符号Quadword整数执行精确除法?代码余数异常求助
x87能否对无符号64位整数执行精确除法?
无符号64位整数精确除法的可行性
x87 FPU虽以有符号数为设计核心,仅明确支持有符号16/32/64位整数类型,但完全可以实现无符号64位整数的精确除法:
- 精度覆盖:x87采用的80位扩展精度浮点数拥有64位尾数(加隐含有效位),可精确表示所有64位整数,包括无符号范围
0~2^64-1的全部数值。 - 运算精确性:根据英特尔手册描述,只要运算的真实结果是整数且在范围内,FPU对整数的运算会返回精确结果。无符号64位除法的商和余数均为整数,符合这一条件。
- 注意事项:
- 加载无符号64位整数时,需用
fild当作有符号数加载。当无符号数大于2^63-1时,会被识别为有符号负数,但FPU对该值的浮点表示仍是精确的。 - 计算余数时,由于FPU余数符号与除数一致(有符号规则),需将余数调整为非负值,以符合无符号除法的要求。
- 加载无符号64位整数时,需用
你的有符号64位除法代码余数为0的原因
你的代码核心错误是栈布局与数据加载不匹配,导致FPU加载的并非输入的被除数和除数,而是寄存器垃圾值,最终出现余数始终为0的异常:
错误点分析
输入的被除数是edx:eax(64位),除数是ecx:ebx(64位),但你执行push edi ecx ebx edx eax后,栈的布局(从esp开始)为:
[esp]:edi(32位)[esp+4]:ecx(32位)[esp+8]:ebx(32位)[esp+12]:edx(32位)[esp+16]:eax(32位)
后续fild qword [edi](即fild qword [esp])加载的是ecx:edi组成的64位值,而非输入的被除数edx:eax;fild qword [edi+8]加载的是edx:ebx组成的64位值,也不是输入的除数ecx:ebx。错误的输入数据导致计算逻辑完全偏离预期,进而出现余数始终为0的情况。
修正后的栈操作示例
正确的做法是按顺序压入被除数和除数的64位数据:
FiDiv: push eax edx ebx ecx ; 先压被除数低32位eax,再压高32位edx;然后压除数低32位ebx,高32位ecx mov edi, esp fninit fild qword [edi] ; 加载被除数(edx:eax,小端序下低地址是eax,高地址是edx) fild qword [edi+8] ; 加载除数(ecx:ebx) ; 后续逻辑保持不变
其他潜在注意点
fninit会将FPU舍入模式重置为“就近舍入”,你后续修改为“向零截断”的操作符合idiv的行为,是正确的。- 你通过
fnstsw检测8000000000000000h / -1的溢出情况并设置CF的逻辑是合理的。
内容的提问来源于stack exchange,提问作者Sep Roland
相关产品推荐
相关产品推荐

