return true;
}
/// Получить указатель на строку с заданным номером (только для чтения).
inline const double* get_row(const Matrix_info *m, size_t i)
{
return m->data + i * m->cols;
}
/// Получить указатель на строку с заданным номером.
inline double* get_row(Matrix_info *m, size_t i)
{
return m->data + i * m->cols;
}
/// Извлечь элемент по номерам строки и столбца.
inline double get_element(const Matrix_info *m, size_t i, size_t j)
{
return m->data[i * m->cols + j];
}
/// Установить элемент с заданными номерами строки и столбца.
inline void set_element(Matrix_info *m, size_t i, size_t j, double value)
{
m->data[i * m->cols + j] = value;
}
#endif//AMATRIX_HPP_INCLUDED_AMA700
0710-transpose_naive.cpp
// transpose_naive.cpp
// Транспонирование матрицы
#include "amatrix.hpp"
/// Создать новую матрицу mt как результат транспонирования m.
void make_transpose_naive(const Matrix_info *m, Matrix_info *mt)
{
// размеры
const auto
rows = m->rows,
cols = m->cols;
// подготовить место
realloc_matrix(mt, cols, rows);
auto m_row = m->data; // начало текущей строки в m
auto mt_col = mt->data; // начало текущего столбца в mt
for (size_t i = 0; i < rows; ++i)
{
auto mt_pos = mt_col; // позиция записи
for (size_t j = 0; j < cols; ++j)
{
// соседние элементы строки идут в массиве друг за другом непосредственно (шаг = 1)
*mt_pos = m_row[j];
// соседние элементы столбца идут в массиве с шагом в одну строку
// (шаг = rows -- количество столбцов в mt)
mt_pos += rows;
}
++mt_col; // перейти на следующий столбец в mt
m_row += cols; // перейти к следующей строке в m
}
// простой вариант:
//for (size_t i = 0; i < rows; ++i)
// for (size_t j = 0; j < cols; ++j)
// mt->data[j * mt->cols + i] = m->data[i * m->cols + j];
// код выше избавлен от умножений
}
///////////////////////////////////////////////////////////////////////////////
#include
#include
/// Тестирование функции, выполняющей транспозицию.
int test_transpose()
{
int result = 0;
Matrix_info m = {}, mt = {}, mt2 = {}; // = {} заполняет поля нулями
// Квадратная матрица, заполненная константой после транспонирования совпдает сама с собой.
alloc_matrix(&m, 100, 100);
fill_matrix(&m, 1.0);
make_transpose_naive(&m, &mt);
// Серия проверок.
if (!matrices_are_equal(&m, &mt))
result = 1;
// Единичная матрица при транспонировании тоже не изменяется.
identity(&m, 90);
make_transpose_naive(&m, &mt);
if (!matrices_are_equal(&m, &mt))
result = 2;
// Теперь сделаем так, чтобы транспонированная матрица не была равна исходной,
// повторное транспонирование должно вернуть исходную матрицу.
set_element(&m, 1, 25, 100.);
make_transpose_naive(&m, &mt);
make_transpose_naive(&mt, &mt2);
if (get_element(&mt, 1, 25) != 0.) result = 3;
if (get_element(&mt, 25, 1) != 100.) result = 4;
if (matrices_are_equal(&m, &mt)) result = 5;
if (!matrices_are_equal(&m, &mt2)) result = 6;
// Освободим память.
free_matrix(&m);
free_matrix(&mt);
return result;
}
int main()
{
using namespace std;
cout << test_transpose() << endl;
return EXIT_SUCCESS;
}
0720-matrix_zero_block.cpp
// matrix_zero_block.cpp
// Требуется определить, являются ли строки или столбцы за пределами максимальной квадратной
// угловой подматрицы нулевыми. В случае, когда исходная матрица квадратная, возвращать истину.
// Формально записать это условие можно следующим образом.
// Пусть A = (a_ij) -- матрица размера n x m.
// Пусть k = min(n, m), проверить, равны ли нулю все элементы a_ij при k
#include "amatrix.hpp"
/// Определить, являются ли внешние по отношению к квадратной подматрице строки или столбцы нулевыми.
bool are_outer_lines_zeroes(const Matrix_info *mtx)
{
const auto data = mtx->data;
const auto rows = mtx->rows, cols = mtx->cols;
if (rows < cols)
{
// Строк меньше, чем столбцов -- проверим "хвосты" строк на равенство нулю.
// Длина "хвоста".
const auto diff = cols - rows;
for (size_t i = 0; i < rows; ++i)
{
// Вычислим указатель на первый элемент "хвоста" i-й строки.
const auto tail = data + i * cols + rows;
// Проверим элементы "хвоста" на равенство нулю.
for (size_t j = 0; j < diff; ++j)
if (tail[j] != 0)
return false;
}
}
else if (cols < rows)
{
// Столбцов меньше, чем строк -- проверим "лишние" строки на равенство нулю.
// Вычислим указатель на первую "лишнюю" строку,
// все последующие элементы массива принадлежат "лишним" строкам, проверим их на равенство нулю.
const auto excess = data + cols * cols;
const auto size = (rows - cols) * cols; // сколько оставшихся элементов
for (size_t i = 0; i < size; ++i)
if (excess[i] != 0)
return false;
}
// Либо матрица является квадратной, либо проверка в ветках if прошла успешно.
return true;
}
///////////////////////////////////////////////////////////////////////////////
// Тестирование
#include
#include
int test_are_outer_lines_zeroes()
{
int result = 0;
Matrix_info m = {};
alloc_matrix(&m, 10, 20);
fill_matrix(&m, 0.);
if (!are_outer_lines_zeroes(&m))
result = 1;
set_element(&m, 5, 15, 42.);
if (are_outer_lines_zeroes(&m))
result = 2;
realloc_matrix(&m, 20, 10);
fill_matrix(&m, 0.);
if (!are_outer_lines_zeroes(&m))
result = 3;
set_element(&m, 15, 5, 42.);
if (are_outer_lines_zeroes(&m))
result = 4;
realloc_matrix(&m, 15, 15);
fill_matrix(&m, 123.);
if (!are_outer_lines_zeroes(&m))
result = 5;
free_matrix(&m);
return result;
}
int main()
{
using namespace std;
cout << test_are_outer_lines_zeroes() << endl;
return EXIT_SUCCESS;
}
0730-matrix_multiply.cpp
// matrix_multiply.cpp
// Тестирование различных вариантов реализации алгоритма умножения матриц "по определению".
#include "amatrix.hpp"
// Закомментировать при отсутствии ассемблерных вариантов:
#define USE_ASSEMBLY_VARIANTS
// Вариант 1 "в лоб".
bool multiply_v1(const Matrix_info *a, const Matrix_info *b, Matrix_info *c)
{
const auto n = a->rows, s = a->cols, m = b->cols;
if (n == 0 || s == 0 || m == 0 || s != b->rows)
return false;
realloc_matrix(c, n, m);
for (size_t i = 0; i < n; ++i)
{
for (size_t k = 0; k < m; ++k)
{
double sum = 0.;
for (size_t j = 0; j < s; ++j)
sum += get_element(a, i, j) * get_element(b, j, k);
set_element(c, i, k, sum);
}
}
return true;
}
// Вариант 2: прямое манипулирование указателями.
bool multiply_v2(const Matrix_info *a, const Matrix_info *b, Matrix_info *c)
{
const auto n = a->rows, s = a->cols, m = b->cols;
const auto b_data = b->data; // Указатель на массив элементов матрицы b.
if (n == 0 || s == 0 || m == 0 || s != b->rows)
return false;
realloc_matrix(c, n, m);
auto a_row = a->data, // Указатель на текущую строку матрицы a.
c_item = c->data; // Указатель на текущий элемент матрицы c.
for (size_t i = 0; i < n; ++i, a_row += s)
{
for (size_t k = 0; k < m; ++k)
{
double sum = 0.;
auto b_item = b_data + k; // k-й столбец в j-й строке матрицы b.
for (size_t j = 0; j < s; ++j, b_item += m)
sum += a_row[j] * (*b_item);
*c_item++ = sum;
}
}
return true;
}
// Вариант 3: последовательный порядок доступа к памяти.
bool multiply_v3(const Matrix_info *a, const Matrix_info *b, Matrix_info *c)
{
const auto n = a->rows, s = a->cols, m = b->cols;
if (n == 0 || s == 0 || m == 0 || s != b->rows)
return false;
realloc_matrix(c, n, m);
fill_matrix(c, 0.);
auto a_row = a->data, // Указатель на текущую строку матрицы a.
c_row = c->data; // Указатель на текущую строку матрицы c.
for (size_t i = 0; i < n; ++i, a_row += s, c_row += m)
{
auto b_row = b->data; // Указатель на текущую строку матрицы b.
for (size_t j = 0; j < s; ++j, b_row += m)
{
const auto aij = a_row[j];
for (size_t k = 0; k < m; ++k)
c_row[k] += aij * b_row[k];
}
}
return true;
}
#ifdef USE_ASSEMBLY_VARIANTS
// Ссылка на процедуру в ассемблерном коде.
extern "C" void addmtxmul(double*, double*, double*, size_t, size_t, size_t);
// Вариант 4: обёртка ассемблерного кода.
bool multiply_v4(const Matrix_info *a, const Matrix_info *b, Matrix_info *c)
{
const auto n = a->rows, s = a->cols, m = b->cols;
if (n == 0 || s == 0 || m == 0 || s != b->rows)
return false;
realloc_matrix(c, n, m);
fill_matrix(c, 0.);
addmtxmul(a->data, b->data, c->data, n, s, m);
return true;
}
#endif//USE_ASSEMBLY_VARIANTS
///////////////////////////////////////////////////////////////////////////////
// Тестирование
#include
#include
#include // begin, end
#include // высокоточный таймер
#include // генераторы (псевдо)случайных чисел
//////////////////////////////
// Тестирование корректности
// Заполнить матрицу случайными целыми числами из диапазона [-100, 100].
void random100_matrix(size_t seed, Matrix_info *m)
{
using namespace std;
// Генератор псевдослучайной последовательности -- "вихрь Мерсенна".
std::mt19937_64 rng(seed);
// Случайное распределение -- равномерное на [-1, 1].
std::uniform_int_distribution<> dist(-100, 100);
// Заполнить матрицу.
const
Do'stlaringiz bilan baham: |