Шаблон классов valarray
Этот шаблон разработан для оптимизации вычислений, производимых над массивами чисел фиксированного размера. Valarray похож на контейнер, но он им не является. Вы не можете динамически и эффективно наращивать его размер. Он, как и контейнер, может изменять свои размеры, используя метод resize, но при этом имеющиеся данные разрушаются. Главным преимуществом использования valarray является эффективность проведения операций сразу над всеми элементами последовательности. Предположим, вы хотите построить график функции у = sin(x) и имеете процедуру, которая сделает это с учетом масштабирования, оцифровки осей и всяких других удобств. Вашей задачей является лишь сформировать данные для графика и подать их на вход этой процедуры. Использование valarray даст преимущество в легкости манипулирования данными и эффективности выполнения. Для простоты выберем шаг изменения координаты х, равный π/3.
Примечание
C целью экономии места я обычно не привожу директивы препроцессора, которые, конечно же, должны предшествовать каждому из рассматриваемых фрагментов. Большинство читателей, я уверен, успешно решают эту проблему сами, так как сообщения об ошибках обычно довольно ясно указывают на недостающее описание. Но при работе с библиотекой STL окно сообщений ведет себя не совсем так, как при работе с MFC. Незначительный пропуск или неточность со стороны программиста порой приводят к лавине предупреждений и ошибок, анализ которых превращается в испытание для нервной системы. Здесь у компании Microsoft еще довольно много работы. Учитывая сказанное, следующий фрагмент приведен со списком директив, необходимых для его работы.
#include <iostream> #include <algorithm> #include <valarray> #include <limits> using namespace std; void main() { //======== Вспомогательные переменные double PI = atan(l.)*4., dx = PI/3., // Шаг изменения xf = 2*PI – dx/2.; // Барьер int i = 0, size = int(ceil(xf/dx)); // Количество точек //======== Создаем два объекта типа valarray valarray<double> vx(size), vy(size); //======== Абсциссы точек вычисляются в цикле for (double х=0.; х < xf; х += dx) vx[i++] = х; //======== Ординаты вычисляются без помощи цикла vy = sin(vx); cout""Valarrays of x and sin(x)\n"; for (i=0; i < size; i++) cout <<"\nx = " << vx[i] <<" у = "<< vy[i]; }
Теперь усложним задачу. Представим, что надо численно продифференцировать функцию, заданную в дискретном множестве точек. Вы знаете, что конечные разности позволяют аппроксимировать производные, то есть производить численное дифференцирование. В STL есть алгоритм adjacent_dif ference, который вычисляет первые конечные разности в указанном диапазоне последовательности. Здесь важно вспомнить, что valarray не является контейнером и поэтому не поддерживает итераторов. Но алгоритмы STL принимают в качестве аргументов как итераторы, так обычные указатели. Мы воспользуемся этим фактом, а также тем, что элементы valarray расположены в памяти подряд.
Результат дифференцирования надо поместить в другую последовательность типа valarray, которую после этого можно эффективно нормировать, поделив сразу все ее элементы на шаг дискретизации вдоль оси х. Добавьте директиву # include <numeric>, вставьте следующий текст в конец предыдущего фрагмента и, пожалуй, увеличьте количество точек, заменив присвоение dx = Pi/З. на dx = Pi/10:
//======= Конструктор создает valarray нужного размера valarray<double> vd(size); //======= Алгоритм вычисляет конечные разности adjacent_difference(&vy[0], &vy[size], &vd[0]); //======= Все элементы valarray делятся на dx vd /= dx; //======= Мы проверяем результат cout <<"\n\nValarray of differences\n"; for (i=l; i < size; i++) cout <<"\nx = " << vx[i] <<" у = "<< vd[i];