我遇到了一个错误,我的无穷大变量不等于无穷大。我什至不确定在哪种情况下。
这是最小的例子:
#include <iostream>
#include <limits>
#include <cmath>
using namespace std;
constexpr auto NT_INF = std::numeric_limits<double>::infinity();
// prints a number byte-by-byte
void printN(double n){
auto tmp = (uint8_t*)&n;
for (int i = 0; i < 8; i++) {
wprintf(L"%4d ", tmp[i]);
}
wprintf(L"\n");
};
double * genNumbers() {
double * numbers = new double[6];
numbers[0] = 100;
numbers[1] = 1;
numbers[2] = 198263783302;
numbers[3] = 198263783302;
numbers[4] = 100;
numbers[5] = 0;
return numbers;
}
int main()
{
// leave no chance for the compiler to optimize variables away
double * numbers = genNumbers();
// floor((100. * 1.) / (198263783302. - 198263783302.)) / 100.;
numbers[5] = floor((numbers[0] * numbers[1]) / (numbers[2] - numbers[3])) / numbers[4];
double number = numbers[5];
printN(number);
printN(NT_INF);
wprintf(L"%f, %f, %d, %d, %d, %d\n", number, NT_INF, number == 1.0 / 0.0, number == NT_INF, isinf(NT_INF), isinf(number));
delete numbers;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我的 GCC 编译器标志是:
-fno-reorder-blocks -ffast-math -march=native -fno-exceptions -Ofast -fmodulo-sched -fgcse-sm -fgcse-las -fno-inline-small-functions -flto=2 -fgcse-lm -fira-region=all
如果你尝试在 onlinegdb 中运行它,那么你会得到类似的结果
0 0 0 0 0 0 240 127
0 0 0 0 0 0 240 127
inf, inf, 1, 1, 1, 0
Run Code Online (Sandbox Code Playgroud)
从输出来看,和NT_INF是number相同的printN。同时,isinf说number不是无穷大...但 printf 说它是???
如果我尝试在本地编译,情况会更糟(我想,这是由于-march=native)。
0 0 0 0 0 0 240 127
0 0 0 0 0 0 240 127
inf, inf, 0, 0, 1, 0
Run Code Online (Sandbox Code Playgroud)
所以这里number变量甚至不等于无穷大,使用简单的==
我完全不知道这个例子(我的真实代码)有什么问题。也许是由于某些标志或它们的组合,但有太多的组合无法尝试。
-ffast-math暗示-ffinite-math-only,这意味着编译器可以在浮点值始终有限(即永远不会无穷大或 NaN)的假设下进行优化。您违反了该假设,因此您的代码具有实际的未定义行为。
请参阅海湾合作委员会文档。
-Ofast顺便说-ffast-math一句,我认为其他几个选项也是多余的。而且,这些选择对我来说似乎很奇怪。一切似乎都在尝试最大性能,但随后您就-fno-reorder-blocks禁用-fno-inline-small-functions了基本优化。
多个编译器选项会导致编译器的行为不符合 C、C++ 和 IEEE 754 标准。如果您不完全理解这些优化选项的作用以及对标准分歧的暗示,则不应使用此类优化选项。