Мне очень нравятся векторы. Они изящны и быстры. Но я знаю, что эта вещь называется валараем. Почему я должен использовать valarray вместо вектора? Я знаю, что valarrays имеют синтаксический сахар, но кроме этого, когда они полезны?C++ valarray vs. vector
ответ
Valarrays (массивы значений) предназначены для передачи некоторой скорости Fortran на C++. Вы бы не сделали valarray указателей, поэтому компилятор может сделать предположения о коде и оптимизировать его лучше. (Основная причина, по которой Fortran настолько быстр, заключается в том, что нет указателя, поэтому не может быть никакого наложения указателя.)
Valarrays также имеют классы, которые позволяют вам нарезать их достаточно легко, хотя эта часть стандарт мог бы использовать немного больше работы. Изменение их размера является разрушительным, и им не хватает итераторов.
Итак, если это номера, с которыми вы работаете, и удобство не все, что важно использовать valarrays. В противном случае векторы намного удобнее.
У Fortran были указатели со времен Fortran 90 – user2023370
Они не предназначены для того, чтобы избежать указателей. C++ 11 определяет begin() и end() в valarray, которые возвращают итераторам к ним –
@ user2023370: вот почему так много пользователей Fortran предпочитают Fortran 77. :) – Michael
Во время стандартизации C++ 98 valarray был спроектирован так, чтобы допускать некоторые быстрые математические вычисления. Тем не менее, в то время Тодд Вельдхуйзен изобрел шаблоны выражений и создал blitz++, и были изобретены аналогичные методы шаблона-мета, что сделало валяры довольно устаревшими до того, как стандарт был даже выпущен. IIRC, первоначальный разработчик (ы) valarray отказался от него на полпути к стандартизации, который (если это правда) тоже ему не помог.
ISTR, что основная причина, по которой он не был удален из стандарта, заключается в том, что никто не нашел времени для тщательного анализа проблемы и написал предложение об ее удалении.
Пожалуйста, помните, что все это смутно помнит слухи. Возьмите это с солью и надейтесь, что кто-то исправляет или подтверждает это.
шаблоны вычетов можно также зачислить в Vandevoorde тоже, правильно? –
@ Никос: Не то, чтобы я знал. Хотя я мог ошибаться. Что у вас есть за это чтение? – sbi
упоминается в книге «C++ Templates - полное руководство», я думаю, что принято считать, что оба изобрели их [самостоятельно] (http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Сайт/статьи/CUJ/2003/0306/cuj0306becker /). –
valarray должен был позволить некоторому совершенствованию векторной обработки FORTRAN стираться на C++. Как-то необходимая поддержка компилятора никогда не происходила.
Книги Josuttis содержат интересный (несколько пренебрежительный) комментарий к valarray (here и here).
Однако Intel теперь, похоже, пересматривает valarray в своих последних выпусках компилятора (например, см. slide 9); это интересная разработка, учитывая, что их четырехпозиционный набор инструкций SIMD SSE планируется объединить с 8-сторонними AVX и 16-сторонними инструкциями Larrabee, и в интересах переносимости, вероятно, будет намного лучше кодировать абстракцию, такую как valarray, чем (скажем) внутренности.
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
.
Итак, хотя я не совсем уверен, что программисты на С ++ начнут использовать в огромных количествах valarray
, есть хотя бы некоторые обстоятельства, при которых он может обеспечить улучшение скорости.
Является ли оно специально запрещенным для хранения произвольных типов объектов внутри valarray? – Mehrdad
@Mehrdad: Да - есть (довольно длинный) список ограничений в [Numeric.Requirements]. Всего за пару примеров все абстрактные классы и исключения запрещены. Он также требует эквивалентности (например) построения копии и последовательности построения по умолчанию, за которой следует назначение. –
@ Джерри Коффин, это страшно. мы обещаем, что мы его не будем использовать. –
Я знаю valarrays есть синтаксический сахар
Я должен сказать, что я не думаю, что std::valarrays
имеют много способ синтаксического сахара. Синтаксис отличается, но я бы не назвал разницу «сахар». API странный. Раздел на std::valarray
s в Язык программирования C++ упоминает этот необычный API и тот факт, что с std::valarray
s ожидается высокая оптимизация, любые сообщения об ошибках, которые вы получаете при их использовании, вероятно, будут неинтуитивными.
Из любопытства, год назад я провел std::valarray
против std::vector
. У меня больше нет кода или точных результатов (хотя вам не составит труда написать свой собственный). Использование GCC I сделало получить небольшое преимущество в производительности при использовании std::valarray
для простой математики, но не для моих реализаций для расчета стандартного отклонения (и, конечно, стандартное отклонение не так сложно, насколько математика идет).
Я подозреваю, что операции над каждым элементом в большом
(ПРИМЕЧАНИЕ, следуя советам от musiphil, мне удалось получить почти идентичные характеристики от std::vector
играют лучше с кешами, чем на
std::valarray
.
vector
и valarray
).
В конце концов, я решил использовать std::vector
, уделяя пристальное внимание таким вещам, как выделение памяти и создание временных объектов.
Оба std::vector
и std::valarray
хранить данные в непрерывном блоке. Тем не менее, они получают доступ к этим данным с использованием разных шаблонов, и, что более важно, API для std::valarray
поощряет различные шаблоны доступа, чем API для std::vector
.
Для примера стандартного отклонения, на определенном этапе мне нужно было найти среднее значение коллекции и разницу между значением каждого элемента и средним значением.
Для std::valarray
, я сделал что-то вроде:
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;
я, возможно, был более умным с std::slice
или std::gslice
. Прошло уже более пяти лет.
Для std::vector
, я сделал что-то вдоль линий:
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));
Сегодня я бы, конечно, написать, что по-другому. Если ничего другого, я бы воспользовался C++ 11 lambdas.
Очевидно, что эти два фрагмента кода делают разные вещи. Например, пример std::vector
не делает промежуточную коллекцию, как пример std::valarray
. Тем не менее, я считаю, что сравнивать их справедливо, потому что различия связаны с различиями между std::vector
и std::valarray
.
Когда я писал этот ответ, я подозревал, что вычитание значения элементов из двух std::valarray
с (последней строкой в std::valarray
примере) будет меньше кэш-дружеским, чем соответствующая строка в std::vector
примере (который бывает также последняя строка).
Оказывается, однако, что
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;
ли то же самое, что и std::vector
например, и имеет практически одинаковую производительность. В конце концов, вопрос в том, какой API вы предпочитаете.
Я не могу думать о какой-либо причине, почему 'std :: vector' будет лучше играть с кешами, чем' std :: valarray'; они оба выделяют единый непрерывный блок памяти для своих элементов. – musiphil
@musiphil Мой ответ слишком длинный для комментария, поэтому я обновил ответ. –
Спасибо за ваш обновленный ответ. – musiphil
C++ 11 Стандарт говорит:
valarray классы массив определяется так, чтобы быть свободными от определенных форм наложения спектров, таким образом позволяя операции на этих классах должны быть оптимизированы.
См. C++ 11 26.6.1-2.
Поскольку я предполагаю, что стандарт определяет, какие формы, вы можете их процитировать? Кроме того, реализованы ли они с помощью кодовых трюков или являются исключениями на основе компилятора для правил псевдонимов в другом месте на этом языке? –
Я нашел одно хорошее применение для valarray. Это использовать valarray, как массивы numpy.
auto x = linspace(0, 2 * 3.14, 100);
plot(x, sin(x) + sin(3.f * x)/3.f + sin(5.f * x)/5.f);
Мы можем реализовать выше valarray.
valarray<float> linspace(float start, float stop, int size)
{
valarray<float> v(size);
for(int i=0; i<size; i++) v[i] = start + i * (stop-start)/size;
return v;
}
std::valarray<float> arange(float start, float step, float stop)
{
int size = (stop - start)/step;
valarray<float> v(size);
for(int i=0; i<size; i++) v[i] = start + step * i;
return v;
}
string psstm(string command)
{//return system call output as string
string s;
char tmp[1000];
FILE* f = popen(command.c_str(), "r");
while(fgets(tmp, sizeof(tmp), f)) s += tmp;
pclose(f);
return s;
}
string plot(const valarray<float>& x, const valarray<float>& y)
{
int sz = x.size();
assert(sz == y.size());
int bytes = sz * sizeof(float) * 2;
const char* name = "plot1";
int shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, bytes);
float* ptr = (float*)mmap(0, bytes, PROT_WRITE, MAP_SHARED, shm_fd, 0);
for(int i=0; i<sz; i++) {
*ptr++ = x[i];
*ptr++ = y[i];
}
string command = "python plot.py ";
string s = psstm(command + to_string(sz));
shm_unlink(name);
return s;
}
Кроме того, нам нужен скрипт python.
import sys, posix_ipc, os, struct
import matplotlib.pyplot as plt
sz = int(sys.argv[1])
f = posix_ipc.SharedMemory("plot1")
x = [0] * sz
y = [0] * sz
for i in range(sz):
x[i], y[i] = struct.unpack('ff', os.read(f.fd, 8))
os.close(f.fd)
plt.plot(x, y)
plt.show()
- 1. C++ Array vs vector
- 2. C++ Vector vs Array (Время)
- 3. vector vs. array в C++
- 4. C++ Boost valarray
- 5. vector :: at vs. vector :: operator []
- 6. Vector vs string
- 7. Vector vs Array Performance
- 8. C++ std :: vector emplace vs insert
- 9. C++ STL Map vs Vector speed
- 10. C++ Array vs Vector performance test explain
- 11. C++ std pair vs vector speedup
- 12. Как инициализировать valarray из вектора?
- 13. Используйте std :: vector :: begin vs begin (vector)
- 14. Когда использовать Eigen :: Vector vs std :: vector?
- 15. push_back vs emplace vs insert in vector in C++
- 16. C++ 11 std :: array vs static array vs std :: vector
- 17. SIMD vs Vector architecture
- 18. stl vector vs array
- 19. CCArray vs. std :: vector
- 20. Связанный список vs Vector
- 21. Vector vs Deque operator []
- 22. Vector clear vs. resize
- 23. Vector vs Collections.synchronizedList (ArrayList)
- 24. Collections.synchronizedList vs Vector
- 25. В каком смысле valarray освобождается от наложения?
- 26. vector <A> vs vector <A*> vs vector <shared_ptr <A>> in C++
- 27. set vs unordered_set vs sorted vector
- 28. Каково будущее std :: valarray?
- 29. valarray divide it's element
- 30. std :: valarray и распараллеливание
Только обдумывал это на днях. Насколько я знаю, это действительно так же, как специализированный математический вектор. – GManNickG
Не делает ли valarray шаблоны выражений? –
Физик Ульрих Мутце предоставляет прецедент для 'valarray' [здесь] (http://goo.gl/QVDJKq) и [здесь] (http://goo.gl/ja7q8d) – lifebalance