auto sz = matrix_size(m);
const auto data = m->data;
for (size_t i = 0; i < sz; ++i)
data[i] = dist(rng);
}
typedef bool (*Mtx_multiply)(const Matrix_info*, const Matrix_info*, Matrix_info*);
int test_multiply(Mtx_multiply mtx_mul)
{
Matrix_info a = {}, b = {}, c = {}, t = {};
// Тестирование на заранее заданных матрицах
const double a_items[5][6] =
{
{ -10, -5, -1, 2, 6, 12 },
{ -8, -4, 0, 1, 5, 10 },
{ -4, -2, -1, 3, 5, 15 },
{ 24, 12, 10, 8, 4, 2 },
{ 16, -10, 30, -20, 18, -6 }
};
matrix_from_array(&a, 5, 6, &a_items[0][0]);
const double b_items[6][4] =
{
{ 1, 2, 3, 4 },
{ 40, 20, 30, 10 },
{ 0, -5, -6, -7 },
{ 3, 5, 7, 11 },
{ 13, 17, 19, 23 },
{ -4, -3, -2, -1 }
};
matrix_from_array(&b, 6, 4, &b_items[0][0]);
const double t_items[5][4] =
{
{ -174, -39, -70, 65 },
{ -140, -36, -62, 44 },
{ -70, 12, 20, 104 },
{ 572, 340, 500, 324 },
{ -186, -94, -218, -46 }
};
matrix_from_array(&t, 5, 4, &t_items[0][0]);
int result = 0;
if (!mtx_mul(&a, &b, &c))
{
result = 1;
}
else if (!matrices_are_equal(&c, &t))
{
double cd[5][4] = {};
memcpy(&cd[0][0], c.data, 20); // для того, чтобы в отладчике можно было увидеть полученную матрицу
result = 2;
}
// Тестирование на случайных матрицах
const size_t Ns[] = { 3, 4, 5, 6, 7, 10, 20, 25, 113 };
const size_t Ss[] = { 5, 7, 8, 9, 3, 11, 23, 25, 37 };
for (size_t i = 0, i_bnd = std::end(Ns) - std::begin(Ns); i < i_bnd; ++i)
{
realloc_matrix(&a, Ns[i], Ss[i]);
random100_matrix(i * 1234, &a);
realloc_matrix(&b, Ss[i], Ns[i]);
random100_matrix(i * 4321, &b);
if (multiply_v1(&a, &b, &t) != mtx_mul(&a, &b, &c))
{
result = 3;
break;
}
if (!matrices_are_equal(&c, &t))
{
result = 4;
break;
}
}
free_matrix(&a);
free_matrix(&b);
free_matrix(&c);
free_matrix(&t);
return result;
}
//////////////////////////
// Тестирование скорости
// Заполнить матрицу случайными числами из диапазона [-1, 1].
void random_matrix(Matrix_info *m)
{
using namespace std;
// Используем системный генератор случайных чисел для генерации зерна псевдослучайной последовательности.
random_device seed_gen;
// Генератор псевдослучайной последовательности -- "вихрь Мерсенна".
std::mt19937_64 rng(seed_gen());
// Случайное распределение -- равномерное на [-1, 1].
std::uniform_real_distribution<> dist(-1., 1.);
// Заполнить матрицу.
const auto sz = matrix_size(m);
const auto data = m->data;
for (size_t i = 0; i < sz; ++i)
data[i] = dist(rng);
}
// Замерить время, потраченное на перемножение.
double test_speed(Mtx_multiply mtx_mul, size_t m, size_t s, size_t n, size_t rounds = 1)
{
using namespace std::chrono;
volatile auto
a = new Matrix_info[rounds],
b = new Matrix_info[rounds],
c = new Matrix_info[rounds];
for (size_t i = 0; i < rounds; ++i)
{
alloc_matrix(a + i, m, s);
alloc_matrix(b + i, s, n);
alloc_matrix(c + i, m, n);
random_matrix(a + i);
random_matrix(b + i);
}
// Стартовый момент времени.
const auto t0 = high_resolution_clock::now();
// rounds раз выполнить перемножение.
for (size_t i = 0; i < rounds; ++i)
mtx_mul(a + i, b + i, c + i);
// Получить продолжительность в секундах (на MSVC 2013 низкая точность).
const auto t1 = high_resolution_clock::now();
for (size_t i = 0; i < rounds; ++i)
{
free_matrix(a + i);
free_matrix(b + i);
free_matrix(c + i);
}
return duration<double>(t1 - t0).count() / rounds;
}
int main()
{
using namespace std;
int v = 1;
Mtx_multiply variants[] =
{
multiply_v1, multiply_v2,
multiply_v3,
#ifdef USE_ASSEMBLY_VARIANTS
multiply_v4
#endif
};
for (auto variant : variants)
cout << v++ << ") " << test_multiply(variant)
#if defined(DEBUG) || defined(_DEBUG)
<< "\n104 x 104 " << test_speed(variant, 104, 104, 104)
#else
<< "\n36 x 36 " << test_speed(variant, 36, 36, 36, 200000) // 32kb in L1
<< "\n104 x 104 " << test_speed(variant, 104, 104, 104, 1000) // 256kb in L2
<< "\n208 x 208 " << test_speed(variant, 208, 208, 208, 200) // 1Mb in L3
<< "\n416 x 416 " << test_speed(variant, 416, 416, 416, 40) // 4Mb in L3
<< "\n590 x 590 " << test_speed(variant, 590, 590, 590, 20) // 8Mb in L3
<< "\n3k x 1k " << test_speed(variant, 3000, 1000, 3000, 5)
<< "\n1k x 3k " << test_speed(variant, 1000, 3000, 1000, 5)
<< "\n2k x 2k " << test_speed(variant, 2000, 2000, 2000, 5)
#endif
<< endl;
return EXIT_SUCCESS;
}
0740-cvarargs.cpp
// cvarargs.cpp
#include
#include
/// Длина вектора с количеством компонент comps.
/// Компоненты вектора передаются параметрами функции.
double vec_len(int comps, ...)
{
std::va_list args;
va_start(args, comps);
double s = 0.0;
while (comps-- > 0)
{
const double arg = va_arg(args, double);
s += arg * arg;
}
va_end(args);
return std::sqrt(s);
}
#include
#include
int main()
{
using namespace std;
cout << vec_len(1, 2.0) << endl
<< vec_len(2, 1.f, 2.f) << endl
<< vec_len(4, 0., 0., -1., 0.) << endl;
return EXIT_SUCCESS;
}
0750-recursion.cpp
// recursion.cpp
// Демонстрация перехода "рекурсия -> рекурсия через "хвостовой" вызов -> итеративное решение (цикл)".
// Примеры: факториал, числа Фибоначчи, линейный поиск, двоичный поиск.
// При запуске выполняет автоматическое тестирование всех вариантов (кроме линейного поиска).
// rec == "recursive"
// tcr == "tail-call recursion"
// itr == "iterative"
///////////////////////////////////////////////////////////////////////////////
// factorial
double rec_fact(unsigned n)
{
return n == 0 ? 1.0 : n * rec_fact(n - 1);
}
double tcr_fact(unsigned n, double fact = 1.0)
{
return n == 0 ? fact : tcr_fact(n - 1, n * fact);
}
double tcr_fact_caller(unsigned n)
{
return tcr_fact(n);
}
double itr_fact_0(unsigned n)
{
double fact = 1.0;
while (true)
{
if (n == 0)
return fact;
const auto old_n = n;
const auto old_fact = fact;
n = old_n - 1;
fact = old_n * old_fact;
}
}
double itr_fact(unsigned n)
{
double fact = 1.0;
for (; n != 0; --n)
fact *= n;
return fact;
}
typedef double (*fact_variant)(unsigned);
int test_fact(fact_variant fact)
{
const unsigned ns[] = { 0, 1, 2, 5, 7, 10 };
const double fs[] = { 1., 1., 2., 120., 5040., 3628800. };
for (unsigned i = 0; i < sizeof(fs) / sizeof(double); ++i)
if (fact(ns[i]) != fs[i])
return i + 1;
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Fibonacci
double rec_fib(unsigned n)
{
return n < 2 ? n : rec_fib(n - 1) + rec_fib(n - 2);
}
double tcr_fib(unsigned n, double a = 0.0, double b = 1.0)
{
return n == 0 ? a : tcr_fib(n - 1, b, a + b);
}
double tcr_fib_caller(unsigned n)
{
return tcr_fib(n);
}
double itr_fib_0(unsigned n)
{
double a = 0.0, b = 1.0;
while (true)
{
if (n == 0)
return a;
const auto old_n = n;
const auto old_a = a, old_b = b;
a = old_b;
b = old_a + old_b;
n = old_n - 1;
}
}
double itr_fib(unsigned n)
{
double a = 0.0, b = 1.0;
while (n-- > 0)
{
const auto sum = a + b;
a = b;
b = sum;
}
return a;
}
typedef double(*fib_variant)(unsigned);
int test_fib(fib_variant fact)
{
const unsigned ns[] = { 0, 1, 2, 4, 6, 10 };
const double fs[] = { 0., 1., 1., 3., 8., 55. };
Do'stlaringiz bilan baham: |