1

我有一个 C 程序,其中包含math.h并使用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给出了一个类似但更详细的错误(请注意,我没有sqrt在 内调用main):

/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
4

2 回答 2

4

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

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

该选项还允许其他与 IEEE-754 标准不同的代码生成选项。应该引发异常、发出 NaN 信号等的操作可能不会被兑现。评论中的例子是sqrt;如果我们将负值传递给sqrt,则结果可能不符合 IEEE-754 标准。试图找到这些不一致的根源远远超过了现代处理器的任何好处。现代 CPU 拥有海量的浮点资源,正确性远比任何错误的效率感更重要。

有非常真实的例子说明在处理浮点数时尊重实数的关联属性会导致不正确的结果。一个例子是Kahan summation。它依赖于浮点运算的非关联属性。还有其他示例,其中对数值算法的仔细分析依赖于 IEEE-754 属性。另一个例子是赫伦的三角形面积公式

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

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

于 2014-08-22T16:17:57.133 回答
1

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

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

于 2014-08-22T04:55:12.787 回答