7 ответов:
Valarrays (массивы значений) предназначены для приведения некоторой скорости Fortran к C++. Вы не сделали бы valarray указателей, чтобы компилятор мог делать предположения о коде и оптимизировать его лучше. (Основная причина, по которой Fortran настолько быстр, заключается в том, что нет типа указателя, поэтому не может быть никакого сглаживания указателя.)
У Valarrays также есть классы, которые позволяют вам нарезать их достаточно простым способом, хотя эта часть стандарта может использовать немного больше работы. Изменение размера они разрушительны и им не хватает итераторов.
Итак, если это числа, с которыми вы работаете, и удобство не так важно, используйте valarrays. В противном случае, векторы просто намного удобнее.
valarray вроде сирота, что родился в неправильном месте в неправильное время. Это попытка оптимизации, довольно конкретно для машин, которые использовались для тяжелой математики, когда она была написана, в частности, векторные процессоры, такие как Crays.
Если вы не имеете дело с довольно небольшими массивами, однако, это, как правило, плохо работает с кэшированием. На большинстве современных машин вы обычно предпочитаете (насколько это возможно) загружать часть массива, выполнять все операции над ним, а затем переходить к следующей части массива.
valarray также должен исключить любую возможность сглаживания, что (по крайней мере теоретически) позволяет компилятору повысить скорость, потому что он более свободен для хранения значения в регистрах. На самом деле, однако, я вовсе не уверен, что любая реальная реализация использует это в какой-либо значительной степени. Я подозреваю, что это скорее проблема с курицей и яйцом-без поддержки компилятора она не стала популярной, и пока она не популярна, никто не будет беспокоиться о работе над своим компилятором для ее поддержки.
есть также сбивающий с толку (буквально) массив вспомогательных классов для использования с valarray. Вы получаете slice, slice_array, gslice и gslice_array, чтобы играть с частями valarray, и заставить его действовать как многомерный массив. Вы также получаете mask_array, чтобы "замаскировать" операцию (например, добавить элементы в x в y, но только в позициях, где z не равен нулю). Чтобы сделать более чем тривиальное использование valarray, вам нужно много узнать об этих вспомогательных классах, некоторые из которых довольно сложны, и ни один из них не кажется (по крайней мере, мне) очень хорошо документированным.
итог: пока он имеет моменты блеска, и может сделать некоторые вещи, довольно аккуратно, есть также некоторые очень веские причины, что это (и почти наверняка останется) непонятных.
Edit (восемь лет спустя, в 2017 году): некоторые из предыдущих стали устаревшими, по крайней мере, в некоторой степени. Например, Intel реализовала оптимизированную версию valarray для своего компилятора. Он использует примитивы интегрированной производительности Intel (Intel IPP) для повышения производительности. Хотя точное улучшение производительности, несомненно, варьируется, быстрый тест с помощью простого кода показано около 2: 1 улучшение скорости, по сравнению с идентичным кодом, скомпилированным со "стандартной" реализацией
valarray.Итак, пока я не совсем уверен, что программисты на C++ начнут использовать
valarrayв огромных количествах, есть по крайней мере некоторые обстоятельства, в которых он может обеспечить повышение скорости.
во время стандартизации C++98, valarray был разработан, чтобы позволить некоторые виды быстрых математических вычислений. Однако примерно в это же время Тодд Велдхейзен изобрел шаблоны выражений и создал блиц++, и были изобретены аналогичные шаблонные мета-методы, которые сделали valarrays довольно устаревшими до того, как стандарт был даже выпущен. IIRC, первоначальный разработчик(ы) valarray отказался от него на полпути к стандартизации, что (если это правда) тоже не помогло.
Истр, что основная причина, по которой он не был удален из стандарта, заключается в том, что никто не нашел времени, чтобы тщательно оценить проблему и написать предложение об ее удалении.
пожалуйста, имейте в виду, однако, что все это смутно помнится понаслышке. возьмите это с солью и надеюсь, что кто-то исправит или подтвердит это.
я знаю, что у valarrays есть какой-то синтаксический сахар
я должен сказать, что я не думаю
std::valarraysесть много синтаксического сахара. Синтаксис другой, но я бы не назвал разницу "сахар."API-это странно. Раздел оstd::valarrays in Язык Программирования C++ упоминает этот необычный API и тот факт, что сstd::valarrays, как ожидается, будут сильно оптимизированы, любые сообщения об ошибках, которые вы получите при их использовании, вероятно, будут не интуитивно понятный.из любопытства, около года назад я сделал косточки
std::valarrayпротивstd::vector. У меня больше нет кода или точных результатов (хотя это не должно быть трудно написать свой собственный). Используя GCC I сделал получите небольшое преимущество в производительности при использованииstd::valarrayдля простой математики, но не для моих реализаций для вычисления стандартного отклонения (и, конечно, стандартное отклонение не так сложно, насколько математика идет).я подозреваю, что операции на каждом пункт в большом(Примечание, следующие советы musiphil, мне удалось получить почти идентичную производительность отstd::vectorиграть лучше с кэшем, чем операции наstd::valarrays.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 лямбда-выражения.
очевидно, что эти два фрагмента кода делать разные вещи. Во-первых,
std::vectorпример не делает промежуточную коллекцию, какstd::valarrayпримере. Тем не менее, я думаю, что справедливо сравнивать их, потому что различия привязан к различиям междуstd::vectorиstd::valarray.когда я писал этот ответ, я подозревал, что вычитания элементов из двух
std::valarrays (последняя строка в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 вы предпочитаете.
valarray должен был позволить некоторые Фортран вектор-обработка благости протереть на C++. Как-то необходимая поддержка компилятора никогда не случалась.
книги Josuttis содержат некоторые интересные (несколько пренебрежительные) комментарии к valarray (здесь и здесь).
тем не менее, Intel теперь, похоже, пересматривает valarray в своих последних выпусках компилятора (например, см. слайд 9); это интересное развитие событий, учитывая, что их 4-полосный набор инструкций SIMD SSE вот-вот будет объединен 8-полосными инструкциями AVX и 16-полосными инструкциями Larrabee, и в интересах переносимости, вероятно, будет намного лучше кодировать с абстракцией, такой как valarray, чем (скажем) встроенные функции.
стандарт 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()

Comments