Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.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++ -Ofast在使用长双精度时生成错误代码 #包括 内部主(空) { int-val=500; printf(“%d\n”,(int)((长双精度)val/500); printf(“%d\n”,(int)((长双精度)500/500)); }_C++_C_Compilation_G++_Compiler Optimization - Fatal编程技术网

C++ -Ofast在使用长双精度时生成错误代码 #包括 内部主(空) { int-val=500; printf(“%d\n”,(int)((长双精度)val/500); printf(“%d\n”,(int)((长双精度)500/500)); }

C++ -Ofast在使用长双精度时生成错误代码 #包括 内部主(空) { int-val=500; printf(“%d\n”,(int)((长双精度)val/500); printf(“%d\n”,(int)((长双精度)500/500)); },c++,c,compilation,g++,compiler-optimization,C++,C,Compilation,G++,Compiler Optimization,显然,它应该输出11。但如果您使用AST的-Ofast编译它,它将输出01,为什么 如果您将500更改为其他值(例如400)并使用-Ofast进行编译,它仍将输出11 带有-Ofast的编译器资源管理器: 这条线似乎是问题的根源 -Ofast 无视严格的标准遵从性-Ofast启用所有-O3优化。它还支持对所有标准兼容程序无效的优化。它打开-ffast math,-fallow存储数据竞争和Fortran专用[…] -ffast math 设置选项-fno math errno,-funsafe

显然,它应该输出
11
。但如果您使用AST的
-Ofast
编译它,它将输出
01
,为什么

如果您将
500
更改为其他值(例如
400
)并使用
-Ofast
进行编译,它仍将输出
11

带有
-Ofast
的编译器资源管理器:

这条线似乎是问题的根源

-Ofast

无视严格的标准遵从性
-Ofast
启用所有
-O3
优化。它还支持对所有标准兼容程序无效的优化。它打开
-ffast math
-fallow存储数据竞争
和Fortran专用[…]

-ffast math

设置选项
-fno math errno
-funsafe math optimizations
-ffinite math only
-fno rounding math
-fno signing nans
-fcx limited range
-fexcess precision=fast

此选项导致定义预处理器宏
\uuu FAST\u MATH\uu

除了AST的
-ofat
之外,任何
-O
选项都不会启用此选项,因为它可能会导致依赖于精确实现IEEE或ISO数学函数规则/规范的程序输出不正确。但是,对于不需要这些规范保证的程序,它可能会产生更快的代码


结论:不要使用
-ffast math
,除非你愿意得到像现在这样的惊喜。

使用
-Ofast
-ffast math
启用,这可能会导致以不同且更快的方式计算某些操作。在您的情况下,
(长双精度)val/500)
可以计算为
(长双精度)val*(1.0L/500))
。当您比较以下功能的
-O2
-Ofast
时,可以在生成的程序集中看到这一点:

long double f(long double a)
{
    return a / 500.0L;
}
使用
-O2
生成的程序集涉及
fdiv
指令,而使用
-Ofast
生成的程序集涉及
fmul
指令,请参阅

接下来,1/500,即0.002,不能用长双精度表示。因此,出现了一些舍入,而且在您的情况下,这种舍入似乎是向下的。这可以通过以下表达式进行检查:

500.0L * (1.0L / 500.0L) < 1.0L
500.0升*(1.0升/500.0升)<1.0升
其计算结果为
true
:。因此,精确存储的乘数是0.002-一些非常小的增量


最后,乘法的结果是500*(0.002-增量)=1-一些小值。当这个值被转换成
int
时,它会被截断,因此
int
中的结果是0。

即使显示的程序段有“问题”,处理浮点数的方法也是错误的

您或多或少会询问程序浮点数是否具有“精确值”——在本例中为“1”。好的,更准确地说,如果值为“<1”或“>=1”的值是“大约”1,那么正好是两个答案的除法极限。但是,正如其他人已经写过的(或者很容易在维基百科中找到,…)浮点数的精度有限。因此,这种偏差可以而且将会发生

因此,得出一个结论:在进行浮点到整数的转换时,应该始终使用舍入,即“(int)round(floating_point_value)”

注:与其他人可能说的或建议相反——我看不出有任何问题——ffast数学计算。唯一的“问题”是在不同计算机上运行某个程序后(按位)比较其结果


我用-ffast数学(实际上是-Ofast)进行所有(科学)计算。但到目前为止,这从来都不是一个问题——因为我预计浮点数会有一些舍入错误(这是真的,不管是否使用-ffast math)——但就我所知,仅此而已。由于我通常使用64位浮点(双精度),这意味着计算精确到大约15到17位十进制数字——最后(少数)位会出现这些不准确的情况——仍然给我提供了很多“精确”的数字——比如说——超过13位,取决于我的计算有多复杂。

val
更改为小于500将得到0。但我不确定您是否认为
(int)(500./500)
显然是1。在第一种情况下,可能是快速优化导致编译器生成的代码乘以
0.0019999999
,而不是除法。在第二种情况下,它可能根本不会在运行时计算。@cigien这不是重点。关键是两个
printf
语句应该输出相同的值,因为它们本质上是
(int)(500./500)
。它们不必输出相同的值。在第二种方法中,编译器可以生成
put(“1”)只是猜测,但我认为启用了
-ffast math
的编译器可以将
/500
计算为
*(1.0/500)
。如果此值向下舍入,则乘以
(长双精度)500
可能会略低于1,并且强制转换为
int
始终会截断,最终将生成
0