我编写了一小段代码,用于累积比std :: accumulate更快的向量值,因为它允许对函数进行向量化。该函数的主要先决条件是累积后不再使用向量。代码如下:
template <typename floatType>
template <typename Iterator>
double Numeric_class<floatType>::AmDestructiveAccumulate(Iterator A, size_t length)
{
if (length == 1)
{
return A[0];
}
Iterator temp_;
while (length > 1)
{
if (length & 1) // odd
{
A[0] += A[length - 1]; // We add the last value which would otherwise be lost.
length >>= 1;
temp_ = A+length;
for (int i = 0; i < length; i++)
{
A[i] += temp_[i];
}
}
else // even
{
length >>= 1;
temp_ = A+length;
for (int i = 0; i < length; i++)
{
A[i] += temp_[i];
}
}
}
return A[0];
}
该函数基本上将向量分成两半并取两半的成对和。在此之后,它将相加的前半部分分成两个相同的长范围,并再次成对地加起来等等。
我将此功能与std::vector<double> data
一起使用。如果我用A称为data.data()。矢量化故事按预期放置,我的执行速度也显着提高。如果我使用data.begin(),则不会进行矢量化。我使用VC2015编译了代码并进行了全面优化。有没有理由为什么对代码的迭代器版本进行矢量化是非法的,或者VC不会这样做,尽管它是合法的。
答案 0 :(得分:2)
核心问题将是A[i] += temp_[i];
。请注意,A
和temp
互为别名,但您[i]
的运行时选项意味着这只是理论上的。现在,[i]
实际意味着什么?如果A
是指针,那只是*(A+i)
的简写,但是当A
是迭代器时,它是一个函数调用。
高效的矢量化要求编译器发现对A[i]
的写入不会影响temp[i]
的后续读取,这是一个非平凡的观察。没有循环携带依赖,但优化器必须能够证明它。