4

我有一个从VS2013转换到VS2015期间出现的问题的小例子。在VS2015中进一步提到的代码示例导致浮点无效操作。VS2015 vs VS2013中的不同优化导致浮点异常

enter image description here

int main() 
{ 
    unsigned int enableBits = _EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID; 

    _clearfp(); 
    _controlfp_s(0, ~enableBits, enableBits); 

    int count = 100; 
    float array[100]; 

    for (int i = 0; i < count; ++i) 
    { 
     array[i] = (float)pow((float)(count - 1 - i)/count, 4); //this causes exception in VS2015 
    } 

    return 0; 
} 

这只发生在释放模式因此它可能是由不同的优化所致。这段代码有什么问题,或者这是VS 2015中的一个错误?

它很难找到像这样的问题,在整个代码库,所以我找一些系统性的修复不是一个解决方法(例如,使用不同的变量,而不是其中工程)

我还检查产生汇编代码,它似乎在VS2013中使用整个128位注册表在一个分区中执行4次浮动操作。在VS2015中,它似乎只做了2次浮动操作,其余的注册表都是零(或一些垃圾),这可能会引入此异常。

导致异常的指令被标记在图片中。

VS2013 VS2013

和VS2015 enter image description here

任何帮助将不胜感激。 谢谢。

+0

嗯。您的代码适用于启用了全面优化的我(版本/ x64)。你的VS是最新的吗?你有什么“特殊的”编译器设置? –

+0

我使用VS2015更新3.我使用标准设置进行发布+优化(最大化速度/ O2)并启用固有功能(是/否) – Bezousek

回答

1

这看起来是使用浮点异常与您进行的交互,但也启用了一些浮点优化。

代码正在做的是它一次执行2次迭代(循环展开),但使用一次4次分割的div(来自XMM寄存器中的4个浮点数)。 XMM寄存器中的高2位浮点数未使用,为零。由于这些时隙中的值的分配结果不被使用,它通常不重要。然而,当你设置自定义的异常处理时,这会引发一个无效的op异常,即使它的生成值不会被使用。

根据我的理解,您的选择是设置/ fp:strict,这会禁用优化,因此请使其工作(但显然会使代码变慢)或删除controlfp调用。

+0

感谢您的评论。严格的设置将有所帮助,但问题是我不知道应该在哪里设置它。我通常有数百个计算文件,不想在任何地方减少它。你知道VS2015 vs VS2013会发生什么,甚至可以在/ fp:精确的情况下运行吗? – Bezousek