Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在「;“双”字;C语言中的数据挖掘与优化_C++_C_Visual Studio_Floating Point - Fatal编程技术网

C++ 在「;“双”字;C语言中的数据挖掘与优化

C++ 在「;“双”字;C语言中的数据挖掘与优化,c++,c,visual-studio,floating-point,C++,C,Visual Studio,Floating Point,我最近分析了一段使用VS2005编译的旧代码,因为“调试”(无优化)和“发布”(/O2/Oi/Ot选项)编译中的数值行为不同。(简化的)代码如下所示: void f(double x1, double y1, double x2, double y2) { double a1, a2, d; a1 = atan2(y1,x1); a2 = atan2(y2,x2); d = a1 - a2; if (d == 0.0) { // NOTE: I know that == on reals is

我最近分析了一段使用VS2005编译的旧代码,因为“调试”(无优化)和“发布”(/O2/Oi/Ot选项)编译中的数值行为不同。(简化的)代码如下所示:

void f(double x1, double y1, double x2, double y2)
{
double a1, a2, d;

a1 = atan2(y1,x1);
a2 = atan2(y2,x2);
d = a1 - a2;
if (d == 0.0) { // NOTE: I know that == on reals is "evil"!
   printf("EQUAL!\n");
}
如果使用相同的值对(例如
f(1,2,1,2)
)调用函数
f
,则预期函数
f
将打印“EQUAL”,但这并不总是发生在“release”中。事实上,编译器对代码进行了优化,就像它是
d=a1-atan2(y2,x2)
一样,并且完全删除了对中间变量
a2
的赋值。此外,它还利用了第二个
atan2()
的结果已经在FPU堆栈上的事实,因此在FPU上重新加载
a1
,并减去值。问题是,FPU以扩展精度(80位)工作,而
a1
是“仅”双精度(64位),因此将第一个
atan2()
的结果保存在内存中实际上会丢失精度。最后,
d
包含扩展精度和双精度之间的“转换错误”

我非常清楚,应该避免使用float/double标识(
=
运算符)。我的问题不是如何检查双打之间的距离。我的问题是关于如何考虑局部变量的“契约”赋值。根据我“天真”的观点,赋值应该强制编译器将值转换为变量类型所表示的精度(在我的例子中是double)。如果变量是“浮动”的呢?如果它们是“int”(奇怪但合法)呢

那么,简言之,C标准对这种情况怎么说

根据我“天真”的观点,赋值应该强制编译器将值转换为变量类型所表示的精度(在我的例子中是double)

是的,这就是C99标准所说的。见下文

那么,简言之,C标准对这种情况怎么说

在某些情况下,C99标准允许以比类型所暗示的更高的精度计算浮点运算:查找
FLT\u EVAL\u METHOD
FP\u CONTRACT
。在中,这两种结构与超精度相关。但我不知道有什么词可以解释为允许编译器任意降低浮点值的精度,从计算精度降低到类型精度。严格按照标准的解释,这种情况只会以确定的方式发生在特定的地点,如作业和演员阵容

最好是阅读与
FLT\u EVAL\u方法相关的部分:

C99允许在超出范围和精度的情况下进行评估 某些规则。这些在5.2.4.2.2第8段中概述:

除了赋值和强制转换(删除所有额外范围和 精度),使用浮点操作数和 需要进行常规算术转换和浮点运算的值 常数的计算格式可能会影响其范围和精度 大于类型所需的值。评价的使用 格式以实现定义的值为特征 飞行评估方法:

Joseph S.Myers接着描述了GCC中的情况,随后发布了他的文章。情况和编译器(以及无数其他编译器)中的情况一样糟糕:

当使用x87浮点时,GCC将FLT_EVAL_方法定义为2。它的 但是,实施不符合C99对 FLT_EVAL_METHOD==2,因为它是由后端实现的 假装处理器支持SFmode和上的操作 DFmode:

  • 有时,根据优化情况,值可能会溢出到 内存处于SFmode或DFmode模式,因此无法预测会丢失多余的精度 而不是在C99指定它丢失的地方
  • 赋值通常不会失去多余的精度,但
    -ffloat store
    可能会使它更有可能这样做


< > C++标准继承了C99的代码<数学> h <代码>,和<代码>数学.h <代码>是定义<代码> FLTYEVALILY方法< /代码>的标头。出于这个原因,你可能会期望C++编译器遵循这一点,但他们似乎并没有认真对待这个问题。即使是G++也不支持
-fexcess precision=standard
,尽管它使用了与GCC相同的后端(自从Joseph S.Myers的文章和附带的补丁以来,GCC就支持此选项)。

我认为该标准没有承诺对库中包含的函数进行浮点返回。但这是我对这个主题的理解,所以不是很有帮助。默认情况下,VisualStudio将精度设置为“精确”,这允许它进行此类优化。你可以试着将它设置为strict,看看会发生什么。如果其他方法都失败了,那么将所有的中间产物都转换为double就可以了。至少在我尝试为一个非常特定的操作获取IEEE特定的行为时,它起了作用,我不想启用全局fp:strict。如果您想消除x87的多余精度,通常会有一个特定的编译标志;在gcc上有
-fexcess precision=standard
(和
-ffloat store
),用于VC++
/fp:strict
@chux VS 2005甚至没有声明实现C99,因此它不必定义
FLT_EVAL_方法
。而且这并不是说编译器在定义它时总是照他们说的做()