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

为何启用-fexcess-precision=standard时GCC会认为相等浮点值不等?

GCC中-fexcess-precision=standard参数对浮点比较的影响分析

先看这段代码:

int main() {
    double v = 1.1;
    return v == 1.1;
}

在32位编译环境下,指定-fexcess-precision=standard参数时程序返回0,不指定时返回1,下面拆解背后的原因:

一、参数导致返回值差异的核心逻辑

当启用-fexcess-precision=standard时,GCC会把代码中的1.1字面量按long double(x86平台下为80位扩展精度)处理——从汇编代码能看到它用TBYTE格式加载这个常量。而变量v是double类型,存储的是1.1的双精度近似值。

这里的关键是:1.1无法用二进制浮点数精确表示,双精度(64位)和扩展精度(80位)对1.1的近似值存在细微差异。启用参数后,比较在long double精度下执行:变量v被加载到FPU后会自动提升为long double精度,但它的原始值是double的近似值;而右边的1.1是直接按long double精度生成的近似值,两者并不相等,因此程序返回0。

不启用该参数时,GCC会把两边的1.1都按double精度处理,比较的是同一个双精度近似值,所以返回1。

GCC官方bug评论里明确说明这是预期行为,并非bug。另外,如果把比较处的1.1强制转换为double(比如写成v == (double)1.1),两边就都按double精度参与比较,差异会直接消失。

二、未优化时出现两次比较的原因

从给出的汇编代码能看到,不管是否启用参数,都出现了两次fucomip指令。这是因为在未开启优化(默认-O0)的情况下,GCC为了严格对应C语言语义、简化编译器实现,会生成冗余代码:

浮点比较会设置FPU状态字,涉及是否非规格化、是否相等、是否无序(比如NaN参与比较)等状态。第一次比较后用setnp处理“非无序”的情况(排除NaN导致的无效比较),第二次比较专门判断数值是否相等,最后通过cmovne指令把两个条件的结果合并成最终返回值。这种冗余是-O0下的正常现象,开启优化(比如-O1)后,编译器会自动合并成一次比较操作。

未启用-fexcess-precision=standard的汇编代码

main:
        push    ebp
        mov     ebp, esp
        and     esp, -8
        sub     esp, 16
        fld     QWORD PTR .LC0
        fstp    QWORD PTR [esp+8]
        fld     QWORD PTR [esp+8]
        fld     QWORD PTR .LC0
        fucomip st, st(1)
        fstp    st(0)
        setnp   al
        mov     edx, 0
        fld     QWORD PTR [esp+8]
        fld     QWORD PTR .LC0
        fucomip st, st(1)
        fstp    st(0)
        cmovne  eax, edx
        movzx   eax, al
        leave
        ret
.LC0:
        .long   -1717986918
        .long   1072798105

启用-fexcess-precision=standard后的汇编代码

main:
        push    ebp
        mov     ebp, esp
        and     esp, -8
        sub     esp, 16
        fld     QWORD PTR .LC0
        fstp    QWORD PTR [esp+8]
        fld     QWORD PTR [esp+8]
        fld     TBYTE PTR .LC1
        fucomip st, st(1)
        setnp   al
        mov     edx, 0
        fld     TBYTE PTR .LC1
        fucomip st, st(1)
        fstp    st(0)
        cmovne  eax, edx
        movzx   eax, al
        leave
        ret
.LC0:
        .long   -1717986918
        .long   1072798105
.LC1:
        .long   -858993459
        .long   -1932735284
        .long   16383

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 13:42:39