На этом шаге мы рассмотрим особености выполнения арифметических операций над массивами значений.
В массивах значений для обращения к элементам определен оператор индексирования []. Как обычно, первому элементу соответствует индекс 0:
va[0] = 3 * va[1] + va[2];
Также для массивов значений определяются все обычные математические операторы (сложение, вычитание, умножение, деление с остатком, изменение знака, поразрядные операторы, операторы сравнения и логические операторы, а также полный набор операторов присваивания). Эти операторы вызываются для каждого элемента массива значений, обрабатываемого в ходе операции. Таким образом, результат операции с массивом значений представляет собой массив значений, размер которого соответствует размеру операндов; этот массив значений содержит результат поэлементных вычислений. Например, рассмотрим следующую команду:
va1 = va2 * va3;
Эта команда эквивалентна последовательности команд:
va1[0] = va2[0] * va3[0]; va1[1] = va2[1] * va3[1]; va1[2] = va2[2] * va3[2]; . . . . .
Если количество элементов в массивах-операндах различно, результат операции не определен.
Конечно, выполнение операций возможно только в том случае, если они поддерживаются типом элементов, а конкретный смысл операции зависит от смысла операции для элементов. Иначе говоря, любая операция с массивом значений сводится к выполнению одинаковых операций с каждым элементом или парой элементов массивов-операндов.
Для бинарных операций один из операндов может быть задан в виде отдельного значения, относящегося к типу элементов. В этом случае значение объединяется с каждым элементом массива значений, переданного во втором операнде. Например, рассмотрим следующую команду:
va1 = 4 * va2;
Эта команда эквивалентна последовательности команд:
va1[0] = 4 * va2[0]; va1[1] = 4 * va2[1]; va1[2] = 4 * va2[2]; . . . . .
Помните, что тип отдельного значения должен точно соответствовать типу элементов массива значений. Приведенный выше пример будет работать только в том случае, если элементы массива значений относятся к типу int. Например, следующая команда недопустима:
std::valarray<double> va(20);
va = 4 * va; // ОШИБКА: несоответствие типов
Правила бинарных операций также распространяются на операторы сравнения. Оператор == не возвращает одну логическую величину - признак равенства массивов. Вместо этого он возвращает новый массив значений того же размера, содержащий элементы типа bool; каждый элемент содержит результат сравнения соответствующей пары элементов. Например, рассмотрим следующий фрагмент:
std::valarray<double> val(10); std::valarray<double> va2(10); std::valarray<double> vab(10); . . . . . vab = (va1 == va2);
В этом фрагменте последняя команда эквивалентна последовательности команд:
vab[0] = (va1[0] == va2[0]); vab[1] = (va1[1] == va2[1]); vab[2] = (va1[2] == va2[2]); . . . . . vab[9] = (va1[9] == va2[9]);
По этой причине массивы значений не могут сортироваться оператором < и не могут использоваться в качестве элементов контейнеров STL, если проверка их на равенство выполняется оператором == (требования к элементам контейнеров STL изложены на 118 шаге).
Следующая программа представляет собой простой пример использования массивов значений:
//--------------------------------------------------------------------------- #include <vcl.h> #include <iostream> #include <valarray> #include <conio.h> //необходимо для getch() #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused using namespace std; std::string ToRus(const std::string &in) { char *buff = new char [in.length()+1]; CharToOem(in.c_str(),buff); std::string out(buff); delete [] buff; return out; } // Вывод массива значений template <class T> void printValarray (const valarray<T>& va) { for (int i=0; i<va.size(); i++) { cout << va[i] << ' '; } cout << endl; } int main (int argc, char* argv[]) { // Определение двух массивов с десятью элементами valarray<double> va1(10), va2(10); // Заполнение первого массива значениями 0.0, 1.1 ... 9.9 for (int i=0; i<10; i++) { va1[i] = i * 1.1; } // Присваивание -1 всем элементам второго массива значений va2 = -1; // Вывод обоих массивов значений cout << ToRus("Вывод массивов зачений:\n"); cout << ToRus("1-й массив:\n"); printValarray(va1); cout << ToRus("2-й массив:\n"); printValarray(va2); // Вывод минимума, максимума и суммы элементов для первого массива cout << ToRus("1-й массив:\n"); cout << ToRus("минимум: ") << va1.min() << endl; cout << ToRus("максимум: ") << va1.max() << endl; cout << ToRus("сумма: ") << va1.sum() << endl; // Присваивание содержимого первого массива второму va2 = va1; // Удаление всех элементов первого массива va1.resize(0); // Повторный вывод обоих массивов значений cout << ToRus("ПОвторный вывод массивов зачений:\n"); cout << ToRus("1-й массив:\n"); printValarray(va1); cout << ToRus("2-й массив:\n"); printValarray(va2); getch(); return 0; } //---------------------------------------------------------------------------
Результат выполнения программы выглядит так:
Рис.1. Результат работы приложения
На следующем шаге мы рассмотрим трансцендентные функции.