C++ valarray по сравнению с вектором

Выезд, как Клапан делает это в Исходном Механизме: http://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking

, Если это для шутера от первого лица, необходимо будет, вероятно, копаться в некоторых темах, как которые они упоминают, такие: прогноз, компенсация и интерполяция.

152
задан gsamaras 22 July 2016 в 19:21
поделиться

5 ответов

Valarrays (value arrays) are intended to bring some of the speed of Fortran to C++. You wouldn't make a valarray of pointers so the compiler can make assumptions about the code and optimise it better. (The main reason that Fortran is so fast is that there is no pointer type so there can be no pointer aliasing.)

Valarrays also have classes which allow you to slice them up in a reasonably easy way although that part of the standard could use a bit more work. Resizing them is destructive and they lack iterators.

So, if it's numbers you are working with and convenience isn't all that important use valarrays. Otherwise, vectors are just a lot more convenient.

67
ответ дан 23 November 2019 в 22:10
поделиться

valarray - сирота, родившаяся не в том месте и не в то время. Это попытка оптимизации, особенно для машин, которые использовались для сложных математических вычислений, когда она была написана - в частности, векторных процессоров, таких как Crays.

Для векторного процессора вы обычно хотели применить одну операцию для всего массива, затем примените следующую операцию ко всему массиву и так далее, пока вы не сделаете все, что вам нужно.

Однако, если вы не имеете дело с довольно маленькими массивами, это имеет тенденцию плохо работать с кешированием. На большинстве современных машин вы обычно предпочитаете (насколько это возможно) загружать часть массива, выполнять с ним все операции, которые вы собираетесь выполнять, а затем переходить к следующей части массива.

valarray также должен исключить любую возможность наложения имен, что (по крайней мере теоретически) позволяет компилятору повысить скорость, поскольку позволяет более свободно хранить значения в регистрах. В действительности, однако, я вовсе не уверен, что какая-либо реальная реализация в какой-то мере использует это преимущество. Я подозреваю, что это скорее проблема типа курицы и яйца - без поддержки компилятора она не стала популярной, и пока она не пользуется популярностью, никто не возьмется за дело, работая над своим компилятором для ее поддержки.

Существует также ошеломляющий (буквально) массив вспомогательных классов для использования с valarray. Вы получаете slice , slice_array , gslice и gslice_array , чтобы играть с частями valarray , и заставить его действовать как многомерный массив. Вы также получаете mask_array , чтобы «замаскировать» операцию (например, добавить элементы из x в y, но только в тех позициях, где z не равно нулю). Чтобы использовать valarray более чем тривиально, вы должны много узнать об этих вспомогательных классах, некоторые из которых довольно сложны и ни один из них не кажется (по крайней мере, мне) хорошо документированным.

Итог: хотя в нем есть моменты блеска и он может делать некоторые вещи довольно аккуратно, есть также несколько очень веских причин, по которым он (и почти наверняка останется) неясным.

Редактировать (восемь лет спустя, в 2017 году): Некоторые из вышеперечисленных устарели, по крайней мере, до некоторой степени. Например, Intel реализовала оптимизированную версию valarray для своего компилятора. Он использует Intel Integrated Performance Primitives (Intel IPP) для повышения производительности. Хотя точное улучшение производительности, несомненно, варьируется, быстрый тест с простым кодом показывает примерно 2: 1 улучшение скорости по сравнению с идентичным кодом, скомпилированным со «стандартной» реализацией valarray .

Итак, пока Я не совсем уверен, что программисты на C ++ начнут использовать valarray в огромных количествах, есть по крайней мере некоторые обстоятельства, при которых он может обеспечить улучшение скорости.

145
ответ дан 23 November 2019 в 22:10
поделиться

Во время стандартизации C ++ 98 valarray был разработан, чтобы позволить какие-то быстрые математические вычисления. Однако примерно в то время Тодд Велдхёйзен изобрел шаблоны выражений и создал blitz ++ , и были изобретены аналогичные методы мета-шаблонов, которые сделали valarrays в значительной степени устаревшими еще до того, как был выпущен стандарт. IIRC, первоначальный разработчик valarray отказался от него на полпути к стандартизации, что (если это правда) ему тоже не помогло.

ISTR утверждает, что основная причина, по которой он не был удален из стандарта, заключается в том, что никто не нашел времени, чтобы тщательно оценить проблему и написать предложение по ее удалению.

Пожалуйста, имейте в виду, что все это смутно помнят слухи. Отнеситесь к этому с недоверием и надейтесь, что кто-то исправит или подтвердит это.

38
ответ дан 23 November 2019 в 22:10
поделиться

I know valarrays have some syntactic sugar

I have to say that I don't think std::valarrays have much in way of syntactic sugar. The syntax is different, but I wouldn't call the difference "sugar." The API is weird. The section on std::valarrays in The C++ Programming Language mentions this unusual API and the fact that, since std::valarrays are expected to be highly optimized, any error messages you get while using them will probably be non-intuitive.

Out of curiosity, about a year ago I pitted std::valarray against std::vector. I no longer have the code or the precise results (although it shouldn't be hard to write your own). Using GCC I did get a little performance benefit when using std::valarray for simple math, but not for my implementations to calculate standard deviation (and, of course, standard deviation isn't that complex, as far as math goes). I suspect that operations on each item in a large std::vector play better with caches than operations on std::valarrays. (NOTE, following advice from musiphil, I've managed to get almost identical performance from vector and valarray).

In the end, I decided to use std::vector while paying close attention to things like memory allocation and temporary object creation.


Both std::vector and std::valarray store the data in a contiguous block. However, they access that data using different patterns, and more importantly, the API for std::valarray encourages different access patterns than the API for std::vector.

For the standard deviation example, at a particular step I needed to find the collection's mean and the difference between each element's value and the mean.

For the std::valarray, I did something like:

std::valarray<double> original_values = ... // obviously I put something here
double mean = original_values.sum() / original_values.size();
std::valarray<double> temp(mean, original_values.size());
std::valarray<double> differences_from_mean = original_values - temp;

I may have been more clever with std::slice or std::gslice. It's been over five years now.

For std::vector, I did something along the lines of:

std::vector<double> original_values = ... // obviously, I put something here
double mean = std::accumulate(original_values.begin(), original_values.end(), 0.0) / original_values.size();

std::vector<double> differences_from_mean;
differences_from_mean.reserve(original_values.size());
std::transform(original_values.begin(), original_values.end(), std::back_inserter(differences_from_mean), std::bind1st(std::minus<double>(), mean));

Today I would certainly write that differently. If nothing else, I would take advantage of C++11 lambdas.

It's obvious that these two snippets of code do different things. For one, the std::vector example doesn't make an intermediate collection like the std::valarray example does. However, I think it's fair to compare them because the differences are tied to the differences between std::vector and std::valarray.

When I wrote this answer, I suspected that subtracting the value of elements from two std::valarrays (last line in the std::valarray example) would be less cache-friendly than the corresponding line in the std::vector example (which happens to also be the last line).

It turns out, however, that

std::valarray<double> original_values = ... // obviously I put something here
double mean = original_values.sum() / original_values.size();
std::valarray<double> differences_from_mean = original_values - mean;

Does the same thing as the std::vector example, and has almost identical performance. In the end, the question is which API you prefer.

27
ответ дан 23 November 2019 в 22:10
поделиться

valarray должен был позволить некоторым возможностям обработки векторных изображений FORTRAN распространиться на C ++. Каким-то образом необходимой поддержки компилятора на самом деле так и не произошло.

Книги Джозаттиса содержат некоторые интересные (несколько пренебрежительные) комментарии к valarray ( здесь и здесь ).

Однако сейчас Intel похоже, пересматривают valarray в своих последних выпусках компилятора (например, см. слайд 9 ); это интересная разработка, учитывая, что к их 4-стороннему набору инструкций SIMD SSE скоро присоединятся 8-сторонние инструкции AVX и 16-сторонние инструкции Larrabee, и в интересах переносимости, вероятно, будет намного лучше кодировать с помощью абстракции вроде valarray, чем (скажем) внутреннее.

23
ответ дан 23 November 2019 в 22:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: