Шаг 430.
Библиотека STL.
Числовые типы. Операции с массивами значений

    На этом шаге мы рассмотрим особености выполнения арифметических операций над массивами значений.

    В массивах значений для обращения к элементам определен оператор индексирования []. Как обычно, первому элементу соответствует индекс 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. Результат работы приложения

    На следующем шаге мы рассмотрим трансцендентные функции.




Предыдущий шаг Содержание Следующий шаг