C++ 取代-01“;加上-02“;“英特尔编译器”选项会导致将FPE设置为小for循环跳闸计数

C++ 取代-01“;加上-02“;“英特尔编译器”选项会导致将FPE设置为小for循环跳闸计数,c++,intel,compiler-optimization,C++,Intel,Compiler Optimization,代码如下: #include <math.h> #include <iostream> #include <omp.h> #include <fenv.h> #include <signal.h> void handler(int sig) { printf("Floating Point Exception\n"); exit(0); } const float alpha=1.5; const unsigned int N

代码如下:

#include <math.h>
#include <iostream>
#include <omp.h>
#include <fenv.h>
#include <signal.h>

void handler(int sig)
{
  printf("Floating Point Exception\n");
  exit(0);
}
const float alpha=1.5;
const unsigned int N=2;
struct Particle
{
  float x, y, z;
  float m;
};
Particle p[N] __attribute__((aligned(64)));
void interaction()
{
  double P=0.0;
#pragma omp parallel for reduction(+:P)
  for(int i=0; i<N; ++i)
  {
    float PP=0.0;
  #pragma simd reduction(+:PP)
  //#pragma novector
    for(int j=0; j<N; ++j) if(i!=j)
    {
      float rdist1=sqrtf((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y)+(p[i].z-p[j].z)*(p[i].z-p[j].z));
      PP+=alpha/rdist1;
    }
    P+=PP;
  }
  std::cout<<"P="<<P<<std::endl;
}
void randomizeBodies()
{
  double pot_en=0.;
  const double pi=3.1415926536;   
  float RADIUS=pow(10.0*N,1.0/3.0);
#pragma omp single
#pragma novector
  for(int i=0; i<N; ++i)
  {
    float DISTANCE=0.0f;
    if(i>0)
    {
      while(DISTANCE<=1.0f)
      {
        float theta=pi*static_cast <float> (rand())/(static_cast <float> (RAND_MAX));
        float phi=2*pi*static_cast <float> (rand())/(static_cast <float> (RAND_MAX));
        float rr=RADIUS*static_cast <float> (rand())/(static_cast <float> (RAND_MAX));
        p[i].x =rr*sin(theta)*cos(phi);
        p[i].y =rr*sin(theta)*sin(phi);
        p[i].z =rr*cos(theta);
        DISTANCE=10000.0f;
      #pragma simd reduction(min:DISTANCE)      
        for(int j=0; j<i; ++j)
        {
          float dij=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y)+(p[i].z-p[j].z)*(p[i].z-p[j].z));
          if(dij<DISTANCE) DISTANCE=dij;
        }
      }
    }
    else
    {
      float theta=pi*static_cast <float> (rand())/(static_cast <float> (RAND_MAX));
      float phi=2*pi*static_cast <float> (rand())/(static_cast <float> (RAND_MAX));
      float rr=RADIUS*static_cast <float> (rand())/(static_cast <float> (RAND_MAX));
      p[i].x =rr*sin(theta)*cos(phi);
      p[i].y =rr*sin(theta)*sin(phi);
      p[i].z =rr*cos(theta);
    }  
  }
#pragma omp parallel for reduction(+:pot_en)
  for(int i=0; i<N; ++i)
  {
    float pp=0.0;
  #pragma simd reduction(+:pp)
  //#pragma novector
    for(int j=0; j<N;  ++j) if(i!=j)
    {
      float rd=sqrtf((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y)+(p[i].z-p[j].z)*(p[i].z-p[j].z));
      pp+=alpha/rd;
    }
    pot_en+=pp;
  }
  pot_en/=2;
  std::cout<<"P="<<pot_en<<std::endl;
}
int main(int argc, char **argv)
{
  feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
  signal(SIGFPE, handler);
  randomizeBodies();
  interaction();
}
使用“-g”可以得到以下输出

Program received signal SIGFPE, Arithmetic exception.
0x00000000004024ab in randomizeBodies ()
at /home/70-gaa/source/GPU/ERROR24/error.cpp:90
90            pp+=alpha/rd;
(gdb) 
N=2,4时。但在N>=8时,它起作用。 如果要评论

 #pragma simd reduction
和取消注释

 #pragma novector
在这两个for循环中,所有内容都在任意N处工作。如果要使用“-01”,所有内容也在任意N处工作。
如果要使用矢量化和“-O2”或“-O3”,程序将在N=2,4时抛出浮点异常,但在N>=8时有效为什么?原则上,我需要使用以下编译行: -DCMAKE_CXX_FLAGS=“-march=native-mtune=native -ipo16-fp型号fast=2-O3-qopt报告=5-mcmodel=large”。 但是“-O3”不起作用。
我使用Intel Core i7-3770 8核CPU,并使用Intel compiler icpc 17.0.1版。

一般答案与相同。没有
-fp model except
的ICC允许编译器生成源代码不允许的导致fp异常的asm,因此这类事情是
feenableexcept
所期望的

你还没有展示足够的asm来给出一个具体的答案,在这个特定的案例中,到底是什么样的优化技巧导致了这种情况


在我的完整代码中,我强烈需要使用“-O2”或“-O3”优化级别选项。我不明白什么是矛盾的事情

因此,请阅读我在上一个答案中链接的英特尔文档,它清楚地解释了这一点

有3个“组”选项(精确/快速/严格),(宽度)和(
除外
或不)。该组的默认值为
fast=1

英特尔®C++编译器15 < /P>的用户和参考指南 由于默认设置为

fast
,因此不能指定
,除非
没有组a或组B关键字

您可以安全地使用以下任一选项:

  • -O3-fp模型精确-fp模型,带
    feenableexcept()的
    除外
  • -O3-fp model fast=2
    ,完全优化的发布/生产版本不使用
    feenableexcept()

如果要使用
feenableexcept()
,则必须使用
-fp模型。否则,编译器将假定导致FP异常不是程序的可见副作用。

“-FP model fast=2”您为什么需要它?一般答案与相同。没有
-fp model except
的ICC允许编译器生成源代码不允许的导致fp异常的asm,因此这类事情是
feenableexcept
所期望的。您是否只询问在这种情况下是什么特定的优化/代码生成策略导致了这种情况?如果你展示了引发错误的asm指令,这会很有帮助。假设那里有一个向量除法,并且除此之外,NI不能使用-fp模型。这是当我尝试使用“-O1-fp model except”编译行:icpc:command-line error:-fp model except与默认的-fp model fast选项冲突时编译器的错误输出。如何覆盖它?你想要冲突的东西。您启用了FPU异常,但对编译器撒谎说它没有启用。你为什么想要这样的东西?谢谢!“因为fast是默认值,所以不能在没有group a或group B关键字的情况下指定except”-这就是为什么我昨天无法使用唯一选项“except”进行编译的原因,明白了。也许这是一个愚蠢的问题,但我不明白为什么如果要注释feenableexcept(),一切都可以在任意N处工作,如果要取消注释,则会在N=2,4处抛出fpe。我认为,如果存在fpe,无论feenableexcept()是开还是关,程序都应该崩溃或给出一个非数字结果或其他结果。当真的存在浮点异常时,它是如何工作并给出正确的结果的?“浮点异常与C++异常无关。当浮点操作引发浮点异常时,浮点环境的状态会发生变化,可以用STD::FESTESTEPT进行测试,但是大多数实现上的C++程序的执行不间断地进行”()。当出现浮点异常时,程序如何进一步执行?它将使用什么值(如果存在fpe,程序如何定义导致fpe的操作结果)?等等:“GNU libc函数feenableexcept()允许捕获浮点异常,从而生成信号SIGFPE。如果使用编译器选项FNONE调用异常,则该信号的处理程序可能会抛出用户定义的C++异常(En.CPyPopy.CO/W/CPP/Nealth/FEnV)。Undersood,如果启用FEN AbabExeExter(),程序将抛出FP异常,如果不是,则不会。但是FPE发生时它如何工作(程序如何定义导致fpe的操作的结果并进一步)?请解释。@并且:它给出了正确的结果,因为FP异常处于临时状态,在这种情况下不使用(例如,尝试快速方式,在NaN上返回慢速方式),或在混合掉的SIMD向量元素中,它不会成为最终结果的一部分。
-fp model no except
的全部要点是启用具有这种副作用的优化。这是什么意思:“混合掉的SIMD向量元素不会成为最终结果的一部分”和FP异常是一种临时情况,在这种情况下不使用?请解释一下。您想说的是,当启用或不启用FPE捕获时,这些情况的值保存在内存的不同位置(或者如您所说,保存在不同的SIMD向量元素中),当禁用FPE抛出时,将采用正确的值,从而得到正确的结果(fpe案例中的元素被简单地抛弃了)?我愿意理解,因为我不理解。
 #pragma novector