为什么Valarray在Visual Studio 2015上如此慢

Why is valarray so slow on Visual Studio 2015?

本文关键字:2015 Studio Valarray Visual 为什么      更新时间:2023-10-16

为了加快库中的计算,我决定使用std::valarray类。文档说:

std :: valarray和助手课程被定义为没有确定的 混叠的形式,从而使这些班级的操作成为 优化与C中关键字限制的效果相似 编程语言。此外,采用的功能和操作员 允许Valarray参数返回代理对象 编译器可以优化诸如v1 = a * v2之类的表达式 v3;作为执行v1 [i] = a * v2 [i] v3 [i]的单个循环;避免任何临时或多次通过。

这正是我所需要的。当我使用G 编译器时,它正如文档中所述的工作。我已经开发了一个简单的示例来测试std::valarray性能:

void check(std::valarray<float>& a)
{
   for (int i = 0; i < a.size(); i++)
      if (a[i] != 7)
         std::cout << "Error" << std::endl;
}
int main()
{
   const int N = 100000000;
   std::valarray<float> a(1, N);
   std::valarray<float> c(2, N);
   std::valarray<float> b(3, N);
   std::valarray<float> d(N);
   auto start = std::chrono::system_clock::now();
   d = a + b * c;
   auto end = std::chrono::system_clock::now();
   std::cout << "Valarr optimized case: "
      << (end - start).count() << std::endl;
   check(d);
   // Optimal single loop case
   start = std::chrono::system_clock::now();
   for (int i = 0; i < N; i++)
      d[i] = a[i] + b[i] * c[i];
   end = std::chrono::system_clock::now();
   std::cout << "Optimal case: " << (end - start).count() << std::endl;
   check(d);
   return 0;
}

在G 上,我得到了:

Valarr optimized case: 1484215
Optimal case: 1472202

似乎所有操作d = a + b * c;确实都放在一个周期中,这在保持性能的同时简化了代码。但是,当我使用Visual&nbsp; Studio; 2015年时,这无效。对于相同的代码,我得到:

Valarr optimized case: 6652402
Optimal case: 1766699

差异几乎是四次;没有优化!为什么std::valarray在2015年的Visual&nbsp" Studio&nbsp"中不需要工作?我做的一切正确吗?我如何解决问题而不放弃std::valarray

我做的一切正确吗?

您正在做正确的事情。问题是在Visual Studio std::valarray实现中。

为什么std::valarray在Visual&nbsp; Studio&nbsp; 2015?

上不需要工作

只需打开任何valarray操作员的实现,例如operator+。您会看到类似(宏扩展之后(:

   template<class _Ty> inline
      valarray<_Ty> operator+(const valarray<_Ty>& _Left,
         const valarray<_Ty>& _Right)
   {
      valarray<TYPE> _Ans(_Left.size());
      for (size_t _Idx = 0; _Idx < _Ans.size(); ++_Idx)
         _Ans[_Idx] = _Left[_Idx] + _Right[_Idx];
      return (_Ans)
   }

您可以看到,创建一个新对象,其中复制操作的结果。确实没有优化。我不知道为什么,但这是事实。看起来在Visual Studio中,仅添加std::valarray才能兼容。

要进行比较,请考虑GNU实施。如您所见,每个操作员返回仅包含操作但不包含数据的模板类_EXPR。实际计算是在分配运算符中执行的,更具体地说是在__valarray_copy函数中执行的。因此,在执行作业之前,所有操作均在代理对象_Expr上执行。只有调用operator=,就可以在单个环中执行的_Expr中存储的操作。这就是为什么您获得G 的好结果的原因。

如何解决问题?

您需要在Internet上找到合适的std::valarray实现,也可以自己编写。您可以将GNU实现作为示例。