我遇到了一个错误,我的变量与无穷大不等于无穷大。我都不确定是哪种情况。
下面是最小的例子:
#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;
}
我的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
所以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
因此,这里的number
变量甚至不等于无穷大,使用简单的==
我完全不知道这个例子(我的真实的代码)有什么问题。也许这是由于一些旗帜或他们的组合,但有太多的组合,以尝试他们。
1条答案
按热度按时间enyaitl31#
-ffast-math
意味着-ffinite-math-only
,这意味着编译器可以在浮点值总是有限的假设下进行优化(即永远不是无穷大或NaN)。你违反了这个假设,所以你的代码有实际的未定义行为。参见GCC documentation。
-Ofast
也意味着-ffast-math
,我认为其他几个选项是多余的。而且,这些选择对我来说很奇怪。一切似乎都在尝试最大化性能,但您有-fno-reorder-blocks
和-fno-inline-small-functions
,它们禁用了基本优化。您的几个编译器选项会导致编译器的行为不符合C、C++和IEEE 754标准。如果您不完全理解这些优化选项对标准散度的作用和含义,则不应使用它们。