Для того чтобы проверить наше решение, выводим на экране произведение A*x
, которое должно быть равно вектору b
(или достаточно близким к нему с учетом ошибок округления). Из-за вероятных ошибок округления мы не можем просто ограничиться инструкцией
if (A*x!=b) error("Неправильное решение");
Поскольку числа с десятичной точкой являются лишь приближением действительных чисел, получим лишь приближенный ответ. В принципе лучше не применять операторы ==
и !=
к результатам вычислений с десятичными точками: такие числа являются лишь приближениями.
В библиотеке Matrix
нет операции умножения матрицы на вектор, поэтому эту функцию нам придется написать самостоятельно.
Vector operator*(const Matrix& m,const Vector& u)
{
const Index n = m.dim1();
Vector v(n);
for (Index i = 0; i < n; ++i) v(i) = dot_product(m[i], u);
return v;
}
И вновь простая операция над объектом класса Matrix
делает за нас большую часть работы. Как указывалось в разделе 24.5.3, операции вывода объектов класса Matrix
описаны в заголовке MatrixIO.h
. Функции random_matrix()
и random_vector()
просто используют случайные числа (раздел 24.7). Читатели могут написать эти функции в качестве упражнения. Имя Index
является синонимом типа индекса, используемого в библиотеке Matrix
, и определено с помощью оператора typedef
(раздел A.15). Этот тип включается в программу с помощью объявления using
.
using Numeric_lib::Index;
24.7. Случайные числа
из стандартной библиотеки есть такой код:
int rand(); // возвращает числа из диапазона
// [0:RAND_MAX]
RAND_MAX // наибольшее число, которое генерирует
// датчик rand()
void srand(unsigned int); // начальное значение датчика
// случайных чисел
Повторяющиеся вызовы функции rand()
генерируют последовательность чисел типа int
, равномерно распределенных в диапазоне [0:RAND_MAX]
. Эта последовательность чисел называется псевдослучайной, потому что она генерируется с помощью математической формулы и с определенного места начинает повторяться (т.е. становится предсказуемой и не случайной). В частности, если мы много раз вызовем функцию rand()
в программе, то при каждом запуске программы получим одинаковые последовательности. Это чрезвычайно полезно для отладки. Если же мы хотим получать разные последовательности, то должны вызывать функцию srand()
с разными значениями. При каждом новом аргументе функции srand()
функция rand()
будет порождать разные последовательности.
Например, рассмотрим функцию random_vector()
, упомянутую в разделе 24.6.3. Вызов функции random_vector(n)
порождает объект класса Matrix
, содержащий n
элементов, представляющих собой случайные числа в диапазоне от [0:n]
:
Vector random_vector(Index n)
{
Vector v(n);
for (Index i = 0; i < n; ++i)
v(i) = 1.0 * n * rand() / RAND_MAX;
return v;
}
Обратите внимание на использование числа 1.0
, гарантирующего, что все вычисления будут выполнены в арифметике с плавающей точкой. Иначе при каждом делении целого числа на RAND_MAX
мы получали бы 0
.
Сложнее получить целое число из заданного диапазона, например [0:max]
. Большинство людей сразу предлагают следующее решение: