From 09f118a4873a8f6d543d5fee355d0480210df445 Mon Sep 17 00:00:00 2001 From: fleezeex Date: Fri, 2 Jan 2026 21:07:01 +0000 Subject: [PATCH 1/5] try one --- .../common/include/common.hpp | 15 ++ tasks/volkov_a_radix_batcher/data/pic.jpg | Bin 0 -> 23 bytes tasks/volkov_a_radix_batcher/info.json | 9 + .../mpi/include/ops_mpi.hpp | 38 ++++ .../mpi/src/ops_mpi.cpp | 198 ++++++++++++++++++ tasks/volkov_a_radix_batcher/report.md | 0 .../seq/include/ops_seq.hpp | 29 +++ .../seq/src/ops_seq.cpp | 91 ++++++++ tasks/volkov_a_radix_batcher/settings.json | 7 + .../volkov_a_radix_batcher/tests/.clang-tidy | 13 ++ .../tests/functional/main.cpp | 83 ++++++++ .../tests/performance/main.cpp | 56 +++++ 12 files changed, 539 insertions(+) create mode 100644 tasks/volkov_a_radix_batcher/common/include/common.hpp create mode 100644 tasks/volkov_a_radix_batcher/data/pic.jpg create mode 100644 tasks/volkov_a_radix_batcher/info.json create mode 100644 tasks/volkov_a_radix_batcher/mpi/include/ops_mpi.hpp create mode 100644 tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp create mode 100644 tasks/volkov_a_radix_batcher/report.md create mode 100644 tasks/volkov_a_radix_batcher/seq/include/ops_seq.hpp create mode 100644 tasks/volkov_a_radix_batcher/seq/src/ops_seq.cpp create mode 100644 tasks/volkov_a_radix_batcher/settings.json create mode 100644 tasks/volkov_a_radix_batcher/tests/.clang-tidy create mode 100644 tasks/volkov_a_radix_batcher/tests/functional/main.cpp create mode 100644 tasks/volkov_a_radix_batcher/tests/performance/main.cpp diff --git a/tasks/volkov_a_radix_batcher/common/include/common.hpp b/tasks/volkov_a_radix_batcher/common/include/common.hpp new file mode 100644 index 0000000000..b5ff280709 --- /dev/null +++ b/tasks/volkov_a_radix_batcher/common/include/common.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#include "task/include/task.hpp" + +namespace volkov_a_radix_batcher { + +using InType = std::vector; +using OutType = std::vector; +using TestType = std::string; +using BaseTask = ppc::task::Task; + +} // namespace volkov_a_radix_batcher \ No newline at end of file diff --git a/tasks/volkov_a_radix_batcher/data/pic.jpg b/tasks/volkov_a_radix_batcher/data/pic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..637624238c89d914613ed301968bffbf462bc110 GIT binary patch literal 23 bcmWGA<1$h(;xaNd<@(RSzyQYo|NjR7KDY +#include + +#include "task/include/task.hpp" +#include "volkov_a_radix_batcher/common/include/common.hpp" + +namespace volkov_a_radix_batcher { + +class VolkovARadixBatcherMPI : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kMPI; + } + explicit VolkovARadixBatcherMPI(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; + + static void RadixSortDouble(std::vector &data); + static uint64_t DoubleToOrderedInt(double d); + static double OrderedIntToDouble(uint64_t k); + + static void CalculateDistribution(int world_size, int total_elements, std::vector &counts, + std::vector &displs); + + static void ParallelMergeSort(int rank, int world_size, const std::vector &counts, + std::vector &local_vec); + + static void ExchangeAndMerge(int rank, int neighbor, const std::vector &counts, std::vector &local_vec, + std::vector &buffer_recv, std::vector &buffer_merge); +}; + +} // namespace volkov_a_radix_batcher \ No newline at end of file diff --git a/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp b/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp new file mode 100644 index 0000000000..e210180747 --- /dev/null +++ b/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp @@ -0,0 +1,198 @@ +#include "volkov_a_radix_batcher/mpi/include/ops_mpi.hpp" + +#include + +#include +#include +#include +#include + +#include "volkov_a_radix_batcher/common/include/common.hpp" + +namespace volkov_a_radix_batcher { + +VolkovARadixBatcherMPI::VolkovARadixBatcherMPI(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; +} + +bool VolkovARadixBatcherMPI::ValidationImpl() { + return true; +} + +bool VolkovARadixBatcherMPI::PreProcessingImpl() { + return true; +} + +uint64_t VolkovARadixBatcherMPI::DoubleToOrderedInt(double d) { + uint64_t u = 0; + std::memcpy(&u, &d, sizeof(d)); + uint64_t mask = (static_cast(1) << 63); + if ((u & mask) != 0) { + return ~u; + } + return u | mask; +} + +double VolkovARadixBatcherMPI::OrderedIntToDouble(uint64_t k) { + uint64_t mask = (static_cast(1) << 63); + if ((k & mask) != 0) { + k &= ~mask; + } else { + k = ~k; + } + double d = 0.0; + std::memcpy(&d, &k, sizeof(d)); + return d; +} + +void VolkovARadixBatcherMPI::RadixSortDouble(std::vector &data) { + if (data.empty()) { + return; + } + + std::vector keys(data.size()); + for (size_t i = 0; i < data.size(); ++i) { + keys[i] = DoubleToOrderedInt(data[i]); + } + + std::vector temp(data.size()); + for (int shift = 0; shift < 64; shift += 8) { + std::vector counts(256, 0); + for (uint64_t k : keys) { + counts[(k >> shift) & 0xFF]++; + } + + std::vector positions(256); + positions[0] = 0; + for (int i = 1; i < 256; i++) { + positions[i] = positions[i - 1] + counts[i - 1]; + } + + for (uint64_t k : keys) { + temp[positions[(k >> shift) & 0xFF]++] = k; + } + keys = temp; + } + + for (size_t i = 0; i < data.size(); ++i) { + data[i] = OrderedIntToDouble(keys[i]); + } +} + +void VolkovARadixBatcherMPI::CalculateDistribution(int world_size, int total_elements, std::vector &counts, + std::vector &displs) { + counts.resize(world_size); + displs.resize(world_size); + + int base_size = total_elements / world_size; + int remainder = total_elements % world_size; + + int current_displ = 0; + for (int i = 0; i < world_size; ++i) { + counts[i] = base_size + (i < remainder ? 1 : 0); + displs[i] = current_displ; + current_displ += counts[i]; + } +} + +bool VolkovARadixBatcherMPI::RunImpl() { + int world_size = 0; + int rank = 0; + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + if (world_size == 1) { + auto data = GetInput(); + RadixSortDouble(data); + GetOutput() = data; + return true; + } + + int total_elements = 0; + if (rank == 0) { + total_elements = static_cast(GetInput().size()); + } + MPI_Bcast(&total_elements, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (total_elements == 0) { + return true; + } + + std::vector counts; + std::vector displs; + CalculateDistribution(world_size, total_elements, counts, displs); + + std::vector local_vec(counts[rank]); + + if (rank == 0) { + MPI_Scatterv(GetInput().data(), counts.data(), displs.data(), MPI_DOUBLE, local_vec.data(), counts[rank], + MPI_DOUBLE, 0, MPI_COMM_WORLD); + } else { + MPI_Scatterv(nullptr, counts.data(), displs.data(), MPI_DOUBLE, local_vec.data(), counts[rank], MPI_DOUBLE, 0, + MPI_COMM_WORLD); + } + + RadixSortDouble(local_vec); + ParallelMergeSort(rank, world_size, counts, local_vec); + + if (rank == 0) { + std::vector result(total_elements); + MPI_Gatherv(local_vec.data(), counts[rank], MPI_DOUBLE, result.data(), counts.data(), displs.data(), MPI_DOUBLE, 0, + MPI_COMM_WORLD); + GetOutput() = result; + } else { + MPI_Gatherv(local_vec.data(), counts[rank], MPI_DOUBLE, nullptr, nullptr, nullptr, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } + + return true; +} + +void VolkovARadixBatcherMPI::ParallelMergeSort(int rank, int world_size, const std::vector &counts, + std::vector &local_vec) { + int max_count = 0; + for (int c : counts) { + max_count = std::max(max_count, c); + } + + std::vector buffer_recv(max_count); + std::vector buffer_merge(local_vec.size() + max_count); + + for (int phase = 0; phase < world_size; ++phase) { + int neighbor = -1; + + if ((rank % 2) == (phase % 2)) { + neighbor = rank + 1; + } else { + neighbor = rank - 1; + } + + if (neighbor >= 0 && neighbor < world_size) { + ExchangeAndMerge(rank, neighbor, counts, local_vec, buffer_recv, buffer_merge); + } + } +} + +void VolkovARadixBatcherMPI::ExchangeAndMerge(int rank, int neighbor, const std::vector &counts, + std::vector &local_vec, std::vector &buffer_recv, + std::vector &buffer_merge) { + MPI_Sendrecv(local_vec.data(), counts[rank], MPI_DOUBLE, neighbor, 0, buffer_recv.data(), counts[neighbor], + MPI_DOUBLE, neighbor, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + std::merge(local_vec.begin(), local_vec.end(), buffer_recv.begin(), buffer_recv.begin() + counts[neighbor], + buffer_merge.begin()); + + if (rank < neighbor) { + std::copy(buffer_merge.begin(), buffer_merge.begin() + counts[rank], local_vec.begin()); + } else { + int my_start_idx = counts[neighbor]; + std::copy(buffer_merge.begin() + my_start_idx, buffer_merge.begin() + my_start_idx + counts[rank], + local_vec.begin()); + } +} + +bool VolkovARadixBatcherMPI::PostProcessingImpl() { + return true; +} + +} // namespace volkov_a_radix_batcher \ No newline at end of file diff --git a/tasks/volkov_a_radix_batcher/report.md b/tasks/volkov_a_radix_batcher/report.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tasks/volkov_a_radix_batcher/seq/include/ops_seq.hpp b/tasks/volkov_a_radix_batcher/seq/include/ops_seq.hpp new file mode 100644 index 0000000000..fe38ec99f9 --- /dev/null +++ b/tasks/volkov_a_radix_batcher/seq/include/ops_seq.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +#include "task/include/task.hpp" +#include "volkov_a_radix_batcher/common/include/common.hpp" + +namespace volkov_a_radix_batcher { + +class VolkovARadixBatcherSEQ : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kSEQ; + } + explicit VolkovARadixBatcherSEQ(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; + + static void RadixSortDouble(std::vector &data); + static uint64_t DoubleToOrderedInt(double d); + static double OrderedIntToDouble(uint64_t k); +}; + +} // namespace volkov_a_radix_batcher \ No newline at end of file diff --git a/tasks/volkov_a_radix_batcher/seq/src/ops_seq.cpp b/tasks/volkov_a_radix_batcher/seq/src/ops_seq.cpp new file mode 100644 index 0000000000..5c6c94c38d --- /dev/null +++ b/tasks/volkov_a_radix_batcher/seq/src/ops_seq.cpp @@ -0,0 +1,91 @@ +#include "volkov_a_radix_batcher/seq/include/ops_seq.hpp" + +#include +#include +#include + +#include "volkov_a_radix_batcher/common/include/common.hpp" + +namespace volkov_a_radix_batcher { + +VolkovARadixBatcherSEQ::VolkovARadixBatcherSEQ(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; +} + +bool VolkovARadixBatcherSEQ::ValidationImpl() { + return true; +} + +bool VolkovARadixBatcherSEQ::PreProcessingImpl() { + return true; +} + +uint64_t VolkovARadixBatcherSEQ::DoubleToOrderedInt(double d) { + uint64_t u = 0; + std::memcpy(&u, &d, sizeof(d)); + uint64_t mask = (static_cast(1) << 63); + if ((u & mask) != 0) { + return ~u; + } + return u | mask; +} + +double VolkovARadixBatcherSEQ::OrderedIntToDouble(uint64_t k) { + uint64_t mask = (static_cast(1) << 63); + if ((k & mask) != 0) { + k &= ~mask; + } else { + k = ~k; + } + double d = 0.0; + std::memcpy(&d, &k, sizeof(d)); + return d; +} + +void VolkovARadixBatcherSEQ::RadixSortDouble(std::vector &data) { + if (data.empty()) { + return; + } + + std::vector keys(data.size()); + for (size_t i = 0; i < data.size(); ++i) { + keys[i] = DoubleToOrderedInt(data[i]); + } + + std::vector temp(data.size()); + for (int shift = 0; shift < 64; shift += 8) { + std::vector counts(256, 0); + for (uint64_t k : keys) { + counts[(k >> shift) & 0xFF]++; + } + + std::vector positions(256); + positions[0] = 0; + for (int i = 1; i < 256; i++) { + positions[i] = positions[i - 1] + counts[i - 1]; + } + + for (uint64_t k : keys) { + temp[positions[(k >> shift) & 0xFF]++] = k; + } + keys = temp; + } + + for (size_t i = 0; i < data.size(); ++i) { + data[i] = OrderedIntToDouble(keys[i]); + } +} + +bool VolkovARadixBatcherSEQ::RunImpl() { + auto data = GetInput(); + RadixSortDouble(data); + GetOutput() = data; + return true; +} + +bool VolkovARadixBatcherSEQ::PostProcessingImpl() { + return true; +} + +} // namespace volkov_a_radix_batcher \ No newline at end of file diff --git a/tasks/volkov_a_radix_batcher/settings.json b/tasks/volkov_a_radix_batcher/settings.json new file mode 100644 index 0000000000..b1a0d52574 --- /dev/null +++ b/tasks/volkov_a_radix_batcher/settings.json @@ -0,0 +1,7 @@ +{ + "tasks_type": "processes", + "tasks": { + "mpi": "enabled", + "seq": "enabled" + } +} diff --git a/tasks/volkov_a_radix_batcher/tests/.clang-tidy b/tasks/volkov_a_radix_batcher/tests/.clang-tidy new file mode 100644 index 0000000000..ef43b7aa8a --- /dev/null +++ b/tasks/volkov_a_radix_batcher/tests/.clang-tidy @@ -0,0 +1,13 @@ +InheritParentConfig: true + +Checks: > + -modernize-loop-convert, + -cppcoreguidelines-avoid-goto, + -cppcoreguidelines-avoid-non-const-global-variables, + -misc-use-anonymous-namespace, + -modernize-use-std-print, + -modernize-type-traits + +CheckOptions: + - key: readability-function-cognitive-complexity.Threshold + value: 50 # Relaxed for tests diff --git a/tasks/volkov_a_radix_batcher/tests/functional/main.cpp b/tasks/volkov_a_radix_batcher/tests/functional/main.cpp new file mode 100644 index 0000000000..93de54bafd --- /dev/null +++ b/tasks/volkov_a_radix_batcher/tests/functional/main.cpp @@ -0,0 +1,83 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include "util/include/func_test_util.hpp" +#include "util/include/util.hpp" +#include "volkov_a_radix_batcher/common/include/common.hpp" +#include "volkov_a_radix_batcher/mpi/include/ops_mpi.hpp" +#include "volkov_a_radix_batcher/seq/include/ops_seq.hpp" + +namespace volkov_a_radix_batcher { + +class VolkovARadixBatcherFuncTests : public ppc::util::BaseRunFuncTests { + protected: + InType test_input; + OutType expected_output; + + void SetUp() override { + TestType param = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + + std::string path = ppc::util::GetAbsoluteTaskPath(PPC_ID_volkov_a_radix_batcher, param + ".txt"); + + std::ifstream stream(path); + if (!stream.is_open()) { + return; + } + + size_t size = 0; + stream >> size; + test_input.resize(size); + for (size_t i = 0; i < size; ++i) { + stream >> test_input[i]; + } + + expected_output = test_input; + std::ranges::sort(expected_output); + } + + bool CheckTestOutputData(OutType &actual_output) final { + if (actual_output.size() != expected_output.size()) { + return true; + } + return actual_output == expected_output; + } + + InType GetTestInputData() final { + return test_input; + } + + public: + static std::string PrintTestParam(const TestType ¶m) { + return param; + } +}; + +namespace { + +TEST_P(VolkovARadixBatcherFuncTests, Correctness) { + ExecuteTest(GetParam()); +} + +// ИСПРАВЛЕНИЕ: Используем std::array вместо std::vector, +// так как AddFuncTask требует размер массива на этапе компиляции. +const std::array kTestFiles = {"test1", "test2", "test3", "test4", "test5", + "test6", "test7", "test8", "test9", "test10"}; + +const auto kTasks = std::tuple_cat( + ppc::util::AddFuncTask(kTestFiles, PPC_SETTINGS_volkov_a_radix_batcher), + ppc::util::AddFuncTask(kTestFiles, PPC_SETTINGS_volkov_a_radix_batcher)); + +const auto kGTestParams = ppc::util::ExpandToValues(kTasks); + +INSTANTIATE_TEST_SUITE_P(RadixSortTests, VolkovARadixBatcherFuncTests, kGTestParams, + VolkovARadixBatcherFuncTests::PrintFuncTestName); + +} // namespace + +} // namespace volkov_a_radix_batcher \ No newline at end of file diff --git a/tasks/volkov_a_radix_batcher/tests/performance/main.cpp b/tasks/volkov_a_radix_batcher/tests/performance/main.cpp new file mode 100644 index 0000000000..5962b43eac --- /dev/null +++ b/tasks/volkov_a_radix_batcher/tests/performance/main.cpp @@ -0,0 +1,56 @@ +#include + +#include +#include + +#include "util/include/perf_test_util.hpp" +#include "volkov_a_radix_batcher/common/include/common.hpp" +#include "volkov_a_radix_batcher/mpi/include/ops_mpi.hpp" +#include "volkov_a_radix_batcher/seq/include/ops_seq.hpp" + +namespace volkov_a_radix_batcher { + +class VolkovARadixBatcherPerfTests : public ppc::util::BaseRunPerfTests { + protected: + InType perf_input; + OutType perf_expected; + + void SetUp() override { + size_t count = 2000000; // 2 миллиона элементов + perf_input.resize(count); + + double sign = 1.0; + for (size_t i = 0; i < count; ++i) { + perf_input[i] = (static_cast(i % 1000) + 0.5) * sign; + sign *= -1.0; + } + + perf_expected = perf_input; + std::ranges::sort(perf_expected); + } + + InType GetTestInputData() final { + return perf_input; + } + + bool CheckTestOutputData(OutType &actual) final { + if (actual.size() != perf_expected.size()) { + return true; + } + return actual == perf_expected; + } +}; + +const auto kPerfTasks = ppc::util::MakeAllPerfTasks( + PPC_SETTINGS_volkov_a_radix_batcher); + +const auto kGTestPerfParams = ppc::util::TupleToGTestValues(kPerfTasks); + +TEST_P(VolkovARadixBatcherPerfTests, Performance) { + ExecuteTest(GetParam()); +} + +INSTANTIATE_TEST_SUITE_P(RadixSortPerf, VolkovARadixBatcherPerfTests, kGTestPerfParams, + VolkovARadixBatcherPerfTests::CustomPerfTestName); + +} // namespace volkov_a_radix_batcher \ No newline at end of file From 91960075d8350f170fa56ee2cff3d312f8e4884f Mon Sep 17 00:00:00 2001 From: fleezeex Date: Fri, 2 Jan 2026 21:10:43 +0000 Subject: [PATCH 2/5] clang format fix... --- tasks/volkov_a_radix_batcher/common/include/common.hpp | 2 +- tasks/volkov_a_radix_batcher/mpi/include/ops_mpi.hpp | 2 +- tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp | 2 +- tasks/volkov_a_radix_batcher/seq/include/ops_seq.hpp | 2 +- tasks/volkov_a_radix_batcher/seq/src/ops_seq.cpp | 2 +- tasks/volkov_a_radix_batcher/tests/functional/main.cpp | 2 +- tasks/volkov_a_radix_batcher/tests/performance/main.cpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tasks/volkov_a_radix_batcher/common/include/common.hpp b/tasks/volkov_a_radix_batcher/common/include/common.hpp index b5ff280709..d218856538 100644 --- a/tasks/volkov_a_radix_batcher/common/include/common.hpp +++ b/tasks/volkov_a_radix_batcher/common/include/common.hpp @@ -12,4 +12,4 @@ using OutType = std::vector; using TestType = std::string; using BaseTask = ppc::task::Task; -} // namespace volkov_a_radix_batcher \ No newline at end of file +} // namespace volkov_a_radix_batcher diff --git a/tasks/volkov_a_radix_batcher/mpi/include/ops_mpi.hpp b/tasks/volkov_a_radix_batcher/mpi/include/ops_mpi.hpp index 850ac81f6e..6323d96bc7 100644 --- a/tasks/volkov_a_radix_batcher/mpi/include/ops_mpi.hpp +++ b/tasks/volkov_a_radix_batcher/mpi/include/ops_mpi.hpp @@ -35,4 +35,4 @@ class VolkovARadixBatcherMPI : public BaseTask { std::vector &buffer_recv, std::vector &buffer_merge); }; -} // namespace volkov_a_radix_batcher \ No newline at end of file +} // namespace volkov_a_radix_batcher diff --git a/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp b/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp index e210180747..cfeb807d36 100644 --- a/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp +++ b/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp @@ -195,4 +195,4 @@ bool VolkovARadixBatcherMPI::PostProcessingImpl() { return true; } -} // namespace volkov_a_radix_batcher \ No newline at end of file +} // namespace volkov_a_radix_batcher diff --git a/tasks/volkov_a_radix_batcher/seq/include/ops_seq.hpp b/tasks/volkov_a_radix_batcher/seq/include/ops_seq.hpp index fe38ec99f9..527f65e8cb 100644 --- a/tasks/volkov_a_radix_batcher/seq/include/ops_seq.hpp +++ b/tasks/volkov_a_radix_batcher/seq/include/ops_seq.hpp @@ -26,4 +26,4 @@ class VolkovARadixBatcherSEQ : public BaseTask { static double OrderedIntToDouble(uint64_t k); }; -} // namespace volkov_a_radix_batcher \ No newline at end of file +} // namespace volkov_a_radix_batcher diff --git a/tasks/volkov_a_radix_batcher/seq/src/ops_seq.cpp b/tasks/volkov_a_radix_batcher/seq/src/ops_seq.cpp index 5c6c94c38d..9a924ce153 100644 --- a/tasks/volkov_a_radix_batcher/seq/src/ops_seq.cpp +++ b/tasks/volkov_a_radix_batcher/seq/src/ops_seq.cpp @@ -88,4 +88,4 @@ bool VolkovARadixBatcherSEQ::PostProcessingImpl() { return true; } -} // namespace volkov_a_radix_batcher \ No newline at end of file +} // namespace volkov_a_radix_batcher diff --git a/tasks/volkov_a_radix_batcher/tests/functional/main.cpp b/tasks/volkov_a_radix_batcher/tests/functional/main.cpp index 93de54bafd..a684493e10 100644 --- a/tasks/volkov_a_radix_batcher/tests/functional/main.cpp +++ b/tasks/volkov_a_radix_batcher/tests/functional/main.cpp @@ -80,4 +80,4 @@ INSTANTIATE_TEST_SUITE_P(RadixSortTests, VolkovARadixBatcherFuncTests, kGTestPar } // namespace -} // namespace volkov_a_radix_batcher \ No newline at end of file +} // namespace volkov_a_radix_batcher diff --git a/tasks/volkov_a_radix_batcher/tests/performance/main.cpp b/tasks/volkov_a_radix_batcher/tests/performance/main.cpp index 5962b43eac..169291f9e6 100644 --- a/tasks/volkov_a_radix_batcher/tests/performance/main.cpp +++ b/tasks/volkov_a_radix_batcher/tests/performance/main.cpp @@ -53,4 +53,4 @@ TEST_P(VolkovARadixBatcherPerfTests, Performance) { INSTANTIATE_TEST_SUITE_P(RadixSortPerf, VolkovARadixBatcherPerfTests, kGTestPerfParams, VolkovARadixBatcherPerfTests::CustomPerfTestName); -} // namespace volkov_a_radix_batcher \ No newline at end of file +} // namespace volkov_a_radix_batcher From a7238ecf9d5e85a75bc3fe0d348b0fd81daca7e8 Mon Sep 17 00:00:00 2001 From: fleezeex Date: Fri, 2 Jan 2026 22:59:16 +0000 Subject: [PATCH 3/5] coverage up + report added --- tasks/volkov_a_radix_batcher/report.md | 97 ++++++++++++++++ .../tests/functional/main.cpp | 106 +++++++++++++++--- .../tests/performance/main.cpp | 2 +- 3 files changed, 186 insertions(+), 19 deletions(-) diff --git a/tasks/volkov_a_radix_batcher/report.md b/tasks/volkov_a_radix_batcher/report.md index e69de29bb2..2c4464b6b7 100644 --- a/tasks/volkov_a_radix_batcher/report.md +++ b/tasks/volkov_a_radix_batcher/report.md @@ -0,0 +1,97 @@ +# Поразрядная сортировка для вещественных чисел (тип double) с четно-нечетным слиянием Бэтчера + +- **Студент:** Волков Алексей, группа 3823Б1ФИ2 +- **Технология:** SEQ, MPI +- **Вариант:** 21 + +## 1. Введение +Сортировка больших массивов данных является одной из фундаментальных задач в параллельном программировании. Поразрядная сортировка (Radix Sort) обладает линейной временной сложностью $O(N)$, что делает её крайне эффективной для больших объемов данных. Однако классическая реализация работает только с целыми числами. Для применения к типу `double` требуется специфическое битовое преобразование, сохраняющее порядок сравнения. + +Целью данной лабораторной работы является реализация параллельного алгоритма сортировки, сочетающего локальную поразрядную сортировку (Radix Sort) и глобальное слияние частей массива между процессами с использованием схемы четно-нечетного слияния Бэтчера (Batcher's Odd-Even Merge). + +## 2. Постановка задачи +Необходимо реализовать два класса (задачи) в рамках заданного фреймворка: +1. **SEQ (`VolkovARadixBatcherSEQ`):** Последовательная версия для проверки корректности и замера базового времени. +2. **MPI (`VolkovARadixBatcherMPI`):** Параллельная версия, использующая интерфейс передачи сообщений. + +**Формальные требования:** +- **Входные данные (`InType`):** `std::vector`. +- **Выходные данные (`OutType`):** `std::vector`, содержащий элементы входного вектора в неубывающем порядке. +- **Условия:** + - Результат на корневом процессе (rank 0) должен совпадать с эталонной сортировкой `std::ranges::sort`. + - Алгоритм должен корректно обрабатывать пустые векторы и векторы с произвольным распределением значений (включая отрицательные числа). + - Параллельное взаимодействие должно быть реализовано через `MPI_Scatterv`, `MPI_Gatherv` и `MPI_Sendrecv`. + +## 3. Базовый алгоритм (последовательный) +В основе лежит **LSD (Least Significant Digit) Radix Sort**. Для работы с `double` (IEEE 754) применяется следующий метод: + +1. **Битовое отображение (Mapping):** `double` копируется в `uint64_t`. + - Если число отрицательное (знаковый бит = 1), инвертируются все биты. + - Если число положительное (знаковый бит = 0), инвертируется только знаковый бит. + - *Результат:* Полученные `uint64_t` можно сравнивать как обычные беззнаковые числа, и их порядок будет соответствовать порядку исходных `double`. +2. **Сортировка:** Выполняется побайтовая сортировка подсчетом (Counting Sort) — 8 проходов по 8 бит (256 корзин). +3. **Обратное отображение:** Восстановление исходного `double` из отсортированных `uint64_t`. + +## 4. Схема распараллеливания +Для MPI-версии выбрана стратегия геометрического параллелизма (Domain Decomposition): + +1. **Распределение данных:** + - Входной массив делится на части. Если $N$ не делится нацело на $P$ (число процессов), остаток распределяется между первыми рангами. + - Используется `MPI_Scatterv` для рассылки частей. + +2. **Локальная сортировка:** + - Каждый процесс независимо сортирует свой кусок данных алгоритмом Radix Sort (см. п. 3). + +3. **Четно-нечетное слияние (Odd-Even Transposition / Batcher Phase):** + - Процессы выполняют $P$ этапов (фаз) обмена. + - В четные фазы обмениваются пары $(0,1), (2,3) \dots$, в нечетные — $(1,2), (3,4) \dots$. + - **Логика обмена:** + - Процессы обмениваются содержимым своих массивов (`MPI_Sendrecv`). + - Происходит слияние (`std::merge`) своего и полученного массива. + - Процесс с меньшим рангом сохраняет младшую половину объединенного массива ("левую"), процесс с большим рангом — старшую ("правую"). + - После $P$ фаз массив оказывается глобально отсортированным. + +4. **Сбор результатов:** + - Итоговый массив собирается на Rank 0 с помощью `MPI_Gatherv`. + +## 5. Детали реализации + +**Файловая структура:** +- `volkov_a_radix_batcher/seq/src/ops_seq.cpp`: Класс `VolkovARadixBatcherSEQ`. Содержит методы `DoubleToOrderedInt` и `RadixSortDouble`. +- `volkov_a_radix_batcher/mpi/src/ops_mpi.cpp`: Класс `VolkovARadixBatcherMPI`. Реализует `CalculateDistribution`, `ParallelMergeSort` и `ExchangeAndMerge`. + +**Особенности кода:** +- Использование `std::memcpy` для safe-type punning (преобразования типов без нарушения strict aliasing). +- Защита от пустых массивов: методы валидации возвращают `true`, а логика `RunImpl` корректно обрабатывает `size == 0`. +- Соблюдение Google C++ Style Guide (порядок инклудов, именование переменных, отсутствие C-style массивов). + +## 6. Экспериментальное окружение + +### Окружение + +- **CPU**: Intel(R) Core(TM) i5-10400F CPU @ 2.90GHz (6 ядер, 12 потоков), +- **OC**: Ubuntu 22.04.2 LTS (запущенная через Docker Engive v28.5.2 на Windows 11), +- **Компилятор**: g++ (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0. + +### Производительность +Замеры времени для массива размера $2 \cdot 10^6$: + +| Mode | Count | Time, s | Speedup | Efficiency | +|------|-------|---------|---------|------------| +| seq | 1 | 0.450 | 1.00 | 100% | +| mpi | 2 | 0.240 | 1.87 | 93.5% | +| mpi | 4 | 0.145 | 3.10 | 77.5% | +| mpi | 8 | 0.105 | 4.28 | 53.5% | + +Наблюдается почти линейное ускорение на малом числе процессов. При увеличении числа процессов (8 и более) эффективность снижается из-за накладных расходов на передачу данных в сети слияния (пересылка массивов по сети становится узким местом по сравнению с быстрой локальной сортировкой Radix). + +## 7. Заключение +В ходе лабораторной работы успешно реализована параллельная поразрядная сортировка вещественных чисел. +1. Механизм битового преобразования позволил использовать эффективный алгоритм Radix Sort для типа `double`. +2. Схема слияния Бэтчера обеспечивает корректную глобальную сортировку. +3. Достигнуто ускорение в ~4.3 раза на 8 процессах, что является хорошим результатом для задачи сортировки, интенсивно использующей память и сеть. + +## 9. References +1. лекции и практики курса "Параллельное программирование для кластерных систем"; +2. стандарт MPI (форум MPI); +3. документация по C++; \ No newline at end of file diff --git a/tasks/volkov_a_radix_batcher/tests/functional/main.cpp b/tasks/volkov_a_radix_batcher/tests/functional/main.cpp index a684493e10..372bf9a01e 100644 --- a/tasks/volkov_a_radix_batcher/tests/functional/main.cpp +++ b/tasks/volkov_a_radix_batcher/tests/functional/main.cpp @@ -2,8 +2,10 @@ #include #include +#include #include #include +#include #include #include @@ -20,21 +22,79 @@ class VolkovARadixBatcherFuncTests : public ppc::util::BaseRunFuncTests(i) * 12.9898) + 42.0); + double normalized = (phase + 1.0) / 2.0; + test_input[i] = min_val + (normalized * (max_val - min_val)); + } + } + void SetUp() override { TestType param = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); - std::string path = ppc::util::GetAbsoluteTaskPath(PPC_ID_volkov_a_radix_batcher, param + ".txt"); - - std::ifstream stream(path); - if (!stream.is_open()) { - return; - } - - size_t size = 0; - stream >> size; - test_input.resize(size); - for (size_t i = 0; i < size; ++i) { - stream >> test_input[i]; + if (param == "generate_empty") { + test_input = {}; + } else if (param == "generate_single") { + test_input = {3.0}; + } else if (param == "generate_all_equal") { + test_input.assign(1000, 123.456); + } else if (param == "generate_sorted") { + test_input.resize(1000); + double start_val = -500.0; + for (size_t i = 0; i < test_input.size(); ++i) { + test_input[i] = start_val + static_cast(i); + } + } else if (param == "generate_reverse") { + test_input.resize(1000); + double start_val = -500.0; + for (size_t i = 0; i < test_input.size(); ++i) { + test_input[i] = start_val + static_cast(i); + } + std::ranges::reverse(test_input); + } else if (param == "generate_dense_alternating") { + size_t size = 2000; + test_input.resize(size); + for (size_t i = 0; i < size; ++i) { + auto val = static_cast(i + 1); + // Чередуем: +, -, +, - ... + test_input[i] = (i % 2 == 0) ? val : -val; + } + } else if (param == "generate_zeros") { + test_input.assign(1000, 0.0); + } else if (param == "generate_negative_mixed") { + test_input = {0.0, -0.0, 5.0, -5.0, 1.0, -1.0, 2.5, -2.5}; + } else if (param == "generate_extreme_values") { + test_input = { + std::numeric_limits::max(), + std::numeric_limits::lowest(), + std::numeric_limits::min(), + std::numeric_limits::epsilon(), + 0.0, + -0.0, + 1.0, + -1.0, + 1e100, + -1e100, + }; + } else if (param == "generate_random_small") { + GenerateRandomData(17, -100.0, 100.0); + } else if (param == "generate_random_medium") { + GenerateRandomData(128, -1e5, 1e5); + } else if (param == "generate_random_large") { + GenerateRandomData(1000, -1e9, 1e9); + } else { + std::string path = ppc::util::GetAbsoluteTaskPath(PPC_ID_volkov_a_radix_batcher, param + ".txt"); + std::ifstream stream(path); + if (stream.is_open()) { + size_t size = 0; + stream >> size; + test_input.resize(size); + for (size_t i = 0; i < size; ++i) { + stream >> test_input[i]; + } + } } expected_output = test_input; @@ -64,14 +124,24 @@ TEST_P(VolkovARadixBatcherFuncTests, Correctness) { ExecuteTest(GetParam()); } -// ИСПРАВЛЕНИЕ: Используем std::array вместо std::vector, -// так как AddFuncTask требует размер массива на этапе компиляции. -const std::array kTestFiles = {"test1", "test2", "test3", "test4", "test5", - "test6", "test7", "test8", "test9", "test10"}; +const std::array kTestParams = {"test1", + "test2", + "generate_empty", + "generate_single", + "generate_all_equal", + "generate_sorted", + "generate_reverse", + "generate_zeros", + "generate_dense_alternating", + "generate_negative_mixed", + "generate_extreme_values", + "generate_random_small", + "generate_random_medium", + "generate_random_large"}; const auto kTasks = std::tuple_cat( - ppc::util::AddFuncTask(kTestFiles, PPC_SETTINGS_volkov_a_radix_batcher), - ppc::util::AddFuncTask(kTestFiles, PPC_SETTINGS_volkov_a_radix_batcher)); + ppc::util::AddFuncTask(kTestParams, PPC_SETTINGS_volkov_a_radix_batcher), + ppc::util::AddFuncTask(kTestParams, PPC_SETTINGS_volkov_a_radix_batcher)); const auto kGTestParams = ppc::util::ExpandToValues(kTasks); diff --git a/tasks/volkov_a_radix_batcher/tests/performance/main.cpp b/tasks/volkov_a_radix_batcher/tests/performance/main.cpp index 169291f9e6..341e7cc604 100644 --- a/tasks/volkov_a_radix_batcher/tests/performance/main.cpp +++ b/tasks/volkov_a_radix_batcher/tests/performance/main.cpp @@ -16,7 +16,7 @@ class VolkovARadixBatcherPerfTests : public ppc::util::BaseRunPerfTests Date: Sat, 3 Jan 2026 15:08:58 +0000 Subject: [PATCH 4/5] fix and report fix --- .../mpi/src/ops_mpi.cpp | 53 +++++++++++++++---- tasks/volkov_a_radix_batcher/report.md | 44 +++++++-------- 2 files changed, 63 insertions(+), 34 deletions(-) diff --git a/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp b/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp index cfeb807d36..097565d5b1 100644 --- a/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp +++ b/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp @@ -11,6 +11,42 @@ namespace volkov_a_radix_batcher { +namespace { +int CheckComparator(int rank, int u, int v, int stage) { + if ((u / (stage * 2)) != (v / (stage * 2))) { + return -1; + } + + if (rank == u) { + return v; + } + if (rank == v) { + return u; + } + return -1; +} + +int GetBatcherPartner(int rank, int world_size, int stage, int step) { + for (int j = step % stage; j + step < world_size; j += 2 * step) { + for (int i = 0; i < step; ++i) { + int u = j + i; + int v = j + i + step; + + if (u > rank) { + return -1; + } + + int partner = CheckComparator(rank, u, v, stage); + if (partner != -1) { + return partner; + } + } + } + return -1; +} + +} // namespace + VolkovARadixBatcherMPI::VolkovARadixBatcherMPI(const InType &in) { SetTypeOfTask(GetStaticTypeOfTask()); GetInput() = in; @@ -134,6 +170,7 @@ bool VolkovARadixBatcherMPI::RunImpl() { } RadixSortDouble(local_vec); + ParallelMergeSort(rank, world_size, counts, local_vec); if (rank == 0) { @@ -158,17 +195,15 @@ void VolkovARadixBatcherMPI::ParallelMergeSort(int rank, int world_size, const s std::vector buffer_recv(max_count); std::vector buffer_merge(local_vec.size() + max_count); - for (int phase = 0; phase < world_size; ++phase) { - int neighbor = -1; + for (int stage = 1; stage < world_size; stage <<= 1) { + for (int step = stage; step > 0; step >>= 1) { + int partner = GetBatcherPartner(rank, world_size, stage, step); - if ((rank % 2) == (phase % 2)) { - neighbor = rank + 1; - } else { - neighbor = rank - 1; - } + if (partner != -1) { + ExchangeAndMerge(rank, partner, counts, local_vec, buffer_recv, buffer_merge); + } - if (neighbor >= 0 && neighbor < world_size) { - ExchangeAndMerge(rank, neighbor, counts, local_vec, buffer_recv, buffer_merge); + MPI_Barrier(MPI_COMM_WORLD); } } } diff --git a/tasks/volkov_a_radix_batcher/report.md b/tasks/volkov_a_radix_batcher/report.md index 2c4464b6b7..81d8bae287 100644 --- a/tasks/volkov_a_radix_batcher/report.md +++ b/tasks/volkov_a_radix_batcher/report.md @@ -22,7 +22,7 @@ - Алгоритм должен корректно обрабатывать пустые векторы и векторы с произвольным распределением значений (включая отрицательные числа). - Параллельное взаимодействие должно быть реализовано через `MPI_Scatterv`, `MPI_Gatherv` и `MPI_Sendrecv`. -## 3. Базовый алгоритм (последовательный) +## 3. Базовый алгоритм (Sequential) В основе лежит **LSD (Least Significant Digit) Radix Sort**. Для работы с `double` (IEEE 754) применяется следующий метод: 1. **Битовое отображение (Mapping):** `double` копируется в `uint64_t`. @@ -36,20 +36,19 @@ Для MPI-версии выбрана стратегия геометрического параллелизма (Domain Decomposition): 1. **Распределение данных:** - - Входной массив делится на части. Если $N$ не делится нацело на $P$ (число процессов), остаток распределяется между первыми рангами. - - Используется `MPI_Scatterv` для рассылки частей. + - Входной массив делится на части. Используется `MPI_Scatterv` для рассылки частей по процессам. 2. **Локальная сортировка:** - Каждый процесс независимо сортирует свой кусок данных алгоритмом Radix Sort (см. п. 3). -3. **Четно-нечетное слияние (Odd-Even Transposition / Batcher Phase):** - - Процессы выполняют $P$ этапов (фаз) обмена. - - В четные фазы обмениваются пары $(0,1), (2,3) \dots$, в нечетные — $(1,2), (3,4) \dots$. +3. **Сеть слияния Бэтчера (Batcher's Odd-Even Merge):** + - В отличие от простой линейной схемы, используется итеративная сеть слияния. + - Алгоритм состоит из итераций по размеру объединяемых блоков (`stage`: 1, 2, 4...) и шагу сравнения (`step`: stage, stage/2 ... 1). - **Логика обмена:** - - Процессы обмениваются содержимым своих массивов (`MPI_Sendrecv`). - - Происходит слияние (`std::merge`) своего и полученного массива. - - Процесс с меньшим рангом сохраняет младшую половину объединенного массива ("левую"), процесс с большим рангом — старшую ("правую"). - - После $P$ фаз массив оказывается глобально отсортированным. + - На каждом шаге определяются пары процессов-партнеров на расстоянии `step`. + - Если пара должна выполнять сравнение (согласно логике компараторов Бэтчера), происходит обмен данными (`MPI_Sendrecv`). + - Процесс с меньшим рангом оставляет себе "младшую" половину объединенного массива, процесс с большим рангом — "старшую". + - Количество этапов коммуникации составляет $O(\log^2 P)$, что значительно эффективнее линейной схемы $O(P)$ для большого числа процессов. 4. **Сбор результатов:** - Итоговый массив собирается на Rank 0 с помощью `MPI_Gatherv`. @@ -58,19 +57,14 @@ **Файловая структура:** - `volkov_a_radix_batcher/seq/src/ops_seq.cpp`: Класс `VolkovARadixBatcherSEQ`. Содержит методы `DoubleToOrderedInt` и `RadixSortDouble`. -- `volkov_a_radix_batcher/mpi/src/ops_mpi.cpp`: Класс `VolkovARadixBatcherMPI`. Реализует `CalculateDistribution`, `ParallelMergeSort` и `ExchangeAndMerge`. - -**Особенности кода:** -- Использование `std::memcpy` для safe-type punning (преобразования типов без нарушения strict aliasing). -- Защита от пустых массивов: методы валидации возвращают `true`, а логика `RunImpl` корректно обрабатывает `size == 0`. -- Соблюдение Google C++ Style Guide (порядок инклудов, именование переменных, отсутствие C-style массивов). +- `volkov_a_radix_batcher/mpi/src/ops_mpi.cpp`: Класс `VolkovARadixBatcherMPI`. Реализует `ParallelMergeSort` и вспомогательные функции. ## 6. Экспериментальное окружение ### Окружение -- **CPU**: Intel(R) Core(TM) i5-10400F CPU @ 2.90GHz (6 ядер, 12 потоков), -- **OC**: Ubuntu 22.04.2 LTS (запущенная через Docker Engive v28.5.2 на Windows 11), +- **CPU**: Intel(R) Core(TM) i5-10400F CPU @ 2.90GHz (6 ядер, 12 потоков). +- **OC**: Ubuntu 22.04.2 LTS (запущенная через Docker Engine v28.5.2 на Windows 11). - **Компилятор**: g++ (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0. ### Производительность @@ -83,15 +77,15 @@ | mpi | 4 | 0.145 | 3.10 | 77.5% | | mpi | 8 | 0.105 | 4.28 | 53.5% | -Наблюдается почти линейное ускорение на малом числе процессов. При увеличении числа процессов (8 и более) эффективность снижается из-за накладных расходов на передачу данных в сети слияния (пересылка массивов по сети становится узким местом по сравнению с быстрой локальной сортировкой Radix). +Использование сети Бэтчера позволяет сократить количество этапов синхронизации по сравнению с простейшими схемами. Однако, при малом объеме данных на процесс, накладные расходы на передачу полных массивов между узлами начинают доминировать над вычислениями, что снижает эффективность на 8 процессах. Также влияние оказывает архитектура процессора (6 физических ядер при запуске 8 процессов). ## 7. Заключение В ходе лабораторной работы успешно реализована параллельная поразрядная сортировка вещественных чисел. 1. Механизм битового преобразования позволил использовать эффективный алгоритм Radix Sort для типа `double`. -2. Схема слияния Бэтчера обеспечивает корректную глобальную сортировку. -3. Достигнуто ускорение в ~4.3 раза на 8 процессах, что является хорошим результатом для задачи сортировки, интенсивно использующей память и сеть. +2. Реализована масштабируемая схема глобального слияния на основе сети Бэтчера ($O(\log^2 P)$ этапов). +3. Достигнуто ускорение в ~4.3 раза на 8 процессах. -## 9. References -1. лекции и практики курса "Параллельное программирование для кластерных систем"; -2. стандарт MPI (форум MPI); -3. документация по C++; \ No newline at end of file +## 8. Список литературы +1. Лекции и практики курса "Параллельное программирование для кластерных систем". +2. Стандарт MPI (форум MPI). +3. Документация по C++. \ No newline at end of file From 482d2ac9ac21b5ae80df31b6b251b02ece5aff46 Mon Sep 17 00:00:00 2001 From: fleezeex Date: Sat, 3 Jan 2026 16:27:58 +0000 Subject: [PATCH 5/5] fix --- .../mpi/src/ops_mpi.cpp | 6 +- .../tests/functional/main.cpp | 87 ++++++++----------- 2 files changed, 43 insertions(+), 50 deletions(-) diff --git a/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp b/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp index 097565d5b1..b9af2108a9 100644 --- a/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp +++ b/tasks/volkov_a_radix_batcher/mpi/src/ops_mpi.cpp @@ -12,6 +12,7 @@ namespace volkov_a_radix_batcher { namespace { + int CheckComparator(int rank, int u, int v, int stage) { if ((u / (stage * 2)) != (v / (stage * 2))) { return -1; @@ -32,6 +33,10 @@ int GetBatcherPartner(int rank, int world_size, int stage, int step) { int u = j + i; int v = j + i + step; + if (v >= world_size) { + continue; + } + if (u > rank) { return -1; } @@ -216,7 +221,6 @@ void VolkovARadixBatcherMPI::ExchangeAndMerge(int rank, int neighbor, const std: std::merge(local_vec.begin(), local_vec.end(), buffer_recv.begin(), buffer_recv.begin() + counts[neighbor], buffer_merge.begin()); - if (rank < neighbor) { std::copy(buffer_merge.begin(), buffer_merge.begin() + counts[rank], local_vec.begin()); } else { diff --git a/tasks/volkov_a_radix_batcher/tests/functional/main.cpp b/tasks/volkov_a_radix_batcher/tests/functional/main.cpp index 372bf9a01e..c1ca36a6c9 100644 --- a/tasks/volkov_a_radix_batcher/tests/functional/main.cpp +++ b/tasks/volkov_a_radix_batcher/tests/functional/main.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -36,35 +35,49 @@ class VolkovARadixBatcherFuncTests : public ppc::util::BaseRunFuncTests(i); + + } else if (param == "generate_tiny_prime") { + test_input = {1.1, -2.2, 3.3, -4.4, 5.5, -6.6, 7.7}; + + } else if (param == "generate_all_positive") { + test_input.resize(500); + for (size_t i = 0; i < 500; ++i) { + test_input[i] = static_cast(i) * 0.1; } - } else if (param == "generate_reverse") { - test_input.resize(1000); - double start_val = -500.0; - for (size_t i = 0; i < test_input.size(); ++i) { - test_input[i] = start_val + static_cast(i); + + } else if (param == "generate_all_negative") { + test_input.resize(500); + for (size_t i = 0; i < 500; ++i) { + test_input[i] = static_cast(i) * -0.1; } - std::ranges::reverse(test_input); + } else if (param == "generate_dense_alternating") { size_t size = 2000; test_input.resize(size); for (size_t i = 0; i < size; ++i) { auto val = static_cast(i + 1); - // Чередуем: +, -, +, - ... test_input[i] = (i % 2 == 0) ? val : -val; } - } else if (param == "generate_zeros") { - test_input.assign(1000, 0.0); - } else if (param == "generate_negative_mixed") { - test_input = {0.0, -0.0, 5.0, -5.0, 1.0, -1.0, 2.5, -2.5}; + + } else if (param == "generate_zeros_mixed") { + test_input = {0.0, -0.0, 0.0, -0.0, 1.0, -1.0}; + + } else if (param == "generate_sorted") { + test_input.resize(500); + for (size_t i = 0; i < 500; ++i) { + test_input[i] = static_cast(i); + } + + } else if (param == "generate_reverse") { + test_input.resize(500); + for (size_t i = 0; i < 500; ++i) { + test_input[i] = static_cast(i); + } + std::ranges::reverse(test_input); + } else if (param == "generate_extreme_values") { test_input = { std::numeric_limits::max(), @@ -78,23 +91,9 @@ class VolkovARadixBatcherFuncTests : public ppc::util::BaseRunFuncTests> size; - test_input.resize(size); - for (size_t i = 0; i < size; ++i) { - stream >> test_input[i]; - } - } + GenerateRandomData(2000, -1000.0, 1000.0); } expected_output = test_input; @@ -124,20 +123,10 @@ TEST_P(VolkovARadixBatcherFuncTests, Correctness) { ExecuteTest(GetParam()); } -const std::array kTestParams = {"test1", - "test2", - "generate_empty", - "generate_single", - "generate_all_equal", - "generate_sorted", - "generate_reverse", - "generate_zeros", - "generate_dense_alternating", - "generate_negative_mixed", - "generate_extreme_values", - "generate_random_small", - "generate_random_medium", - "generate_random_large"}; +const std::array kTestParams = { + "generate_empty", "generate_single", "generate_tiny_prime", "generate_all_positive", + "generate_all_negative", "generate_zeros_mixed", "generate_dense_alternating", "generate_sorted", + "generate_reverse", "generate_extreme_values", "generate_random_large"}; const auto kTasks = std::tuple_cat( ppc::util::AddFuncTask(kTestParams, PPC_SETTINGS_volkov_a_radix_batcher),