Я написал небольшой фрагмент кода, который я использую для накопления значений вектора, который быстрее, чем std :: accumulate, потому что он позволяет функции векторизация. Основной предпосылкой для функции является то, что вектор больше не используется после накопления. Код выглядит следующим образом:Для вектора вектора вектора с использованием указателей стиля C, но не с использованием итераторов
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 просто не делает этого, хотя это будет законным.
TBH это звучит как ужасный алгоритм, и впечатляет, что оптимизатору удается спасти хотя бы некоторые версии. Вы превратили алгоритм O (N) линейного доступа в вариант O (N log N) с нелинейным доступом. – MSalters
@MSalters Это неверно. Доступ по-прежнему равен O (N). Это N + N/2 + N/4 + N/8 .... Этот геометрический ряд сходится к N * 2. Кроме того, доступ является линейным на каждой итерации. И последнее, но не менее важное: профилирование показывает увеличение производительности для соответствующего N. –
Справедливая точка, она выглядела как две внутренние петли длины N/2, для нечетных и четных, но используется только одна из двух, поэтому это не 'N + 2 * (N/2) + 4 * (N/4) + ... '. – MSalters