除-Ofast以外的任何内容都会导致“未定义的引用”错误

我有一个包含math.h的C程序,并使用该头文件中的sqrt函数。 非常奇怪的是,当我没有传递-Ofast标志时,我的代码无法编译。

如果我使用以下代码编译我的代码:

 gcc -std=c99 foo.c 

要么本身,要么添加任何-O1-O2-Os (那些是大写的O)到该命令,我得到以下错误:

 /tmp/ccAcT2Bz.o: In function `sum_of_divisors': foo.c:(.text+0xb): undefined reference to `sqrt' collect2: error: ld returned 1 exit status 

-O3给出了一个类似但更精细的错误(请注意,我不在main调用sqrt ):

 /tmp/ccBKvvFS.o: In function `sum_of_divisors': foo.c:(.text+0x5c): undefined reference to `sqrt' /tmp/ccBKvvFS.o: In function `main': foo.c:(.text.startup+0xe5): undefined reference to `sqrt' foo.c:(.text.startup+0xf3): undefined reference to `sqrt' collect2: error: ld returned 1 exit status 

但是, -Ofast编译时没有错误,程序运行完美。 所以,

  • 为什么会这样? 为什么必须为其编译启用某个优化级别? 这是GCC的错误吗?
  • 如果我选择不使用-Ofast ,我该如何解决?

我将尝试根据我提供的评论将此作为答案。

基本上-ffast-math允许不符合IEEE-754标准的数学“优化”。 一些例子包括允许浮点运算遵守相关性定律,例如,它们表现得像“实数”: (a + b) + c == a + (b + c) – 这不是一个正确的假设浮点数字。 您可以查看gcc的手册页以查看-ffast-math启用的选项。

该选项还允许其他代码生成选项偏离IEEE-754标准。 应该引起exception,信号NaN等的操作可能不会受到尊重。 评论中的例子是sqrt ; 如果我们将负值传递给sqrt ,结果可能不符合IEEE-754标准。 试图找到这些不一致的来源远远超过现代处理器的任何好处。 现代CPU具有大量的浮点资源,正确性远比任何错位的效率感更重要。

有一些非常实际的例子,当处理浮点数时,尊重实数的关联属性会导致错误的结果。 一个例子是Kahan求和 。 它依赖于浮点运算的非关联属性。 还有其他一些例子,仔细分析数值算法依赖于IEEE-754属性。 另一个例子是Heron的三角形区域公式 。

数值分析是一个广泛的领域,IEEE-754标准代表了一种非常仔细和充分研究的努力,以标准化浮点运算的特殊行为,以及它们与“真实”数字的天真理想的偏差。 它代表了数十年的研究和经验(更不用说挫折)在数字密集计算中的巨大努力。

有些人经常在这个网站上回答浮点问题,而且对这个主题的了解要比我更广泛。 我只是希望让你相信 – 在许多情况下, -ffast-math通常是不明智的(通常一个具有更好数值条件的算法是更好的第一步),并引入极难找到的错误源,结果是通常无法在其他平台上重现。 像瘟疫一样避免它。

构建可执行文件时,必须链接数学库

所以你需要使用-lm选项进行编译。