From 36b1a80b16a6f452ec37cfa7c251a842a97af6f1 Mon Sep 17 00:00:00 2001 From: jambii1 Date: Sat, 1 Nov 2025 14:15:08 +0000 Subject: [PATCH 1/3] [M1] Initial commit --- M1/main.cpp | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 M1/main.cpp diff --git a/M1/main.cpp b/M1/main.cpp new file mode 100644 index 0000000..0c87b37 --- /dev/null +++ b/M1/main.cpp @@ -0,0 +1,2 @@ +int main() +{} From 51fc32022a30a6d506ae68f0ca42448db6e7985e Mon Sep 17 00:00:00 2001 From: jambii1 Date: Sun, 2 Nov 2025 14:06:46 +0000 Subject: [PATCH 2/3] [M1] Add task without multithreading --- M1/generate_points_in_square.cpp | 27 ++++++++++++ M1/generate_points_in_square.hpp | 12 +++++ M1/get_circle_area.cpp | 32 ++++++++++++++ M1/get_circle_area.hpp | 12 +++++ M1/main.cpp | 75 +++++++++++++++++++++++++++++++- M1/point.hpp | 11 +++++ 6 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 M1/generate_points_in_square.cpp create mode 100644 M1/generate_points_in_square.hpp create mode 100644 M1/get_circle_area.cpp create mode 100644 M1/get_circle_area.hpp create mode 100644 M1/point.hpp diff --git a/M1/generate_points_in_square.cpp b/M1/generate_points_in_square.cpp new file mode 100644 index 0000000..d393a2e --- /dev/null +++ b/M1/generate_points_in_square.cpp @@ -0,0 +1,27 @@ +#include "generate_points_in_square.hpp" + +#include +#include + +void rndm::generatePointsInSquare(unsigned radius, unsigned tries, unsigned seed, std::vector< geom::Point >& points) +{ + if (radius == 0 || tries == 0 || !points.empty()) { + throw std::invalid_argument("generatePointsInSquare: invalid arguments"); + + return; + } + + double minX = 0.0, maxX = 2.0 * radius; + double minY = 0.0, maxY = 2.0 * radius; + + std::mt19937 gen(seed); + std::uniform_real_distribution< double > distX(minX, maxX); + std::uniform_real_distribution< double > distY(minY, maxY); + + for (unsigned long i = 0ul; i != tries; ++i) { + double x = distX(gen); + double y = distY(gen); + + points.push_back({x, y}); + } +} diff --git a/M1/generate_points_in_square.hpp b/M1/generate_points_in_square.hpp new file mode 100644 index 0000000..3fa15ea --- /dev/null +++ b/M1/generate_points_in_square.hpp @@ -0,0 +1,12 @@ +#ifndef M1_GENERATE_POINTS_IN_SQUARE_HPP +#define M1_GENERATE_POINTS_IN_SQUARE_HPP + +#include + +#include "point.hpp" + +namespace rndm { + void generatePointsInSquare(unsigned radius, unsigned tries, unsigned seed, std::vector< geom::Point >& points); +} + +#endif diff --git a/M1/get_circle_area.cpp b/M1/get_circle_area.cpp new file mode 100644 index 0000000..868634d --- /dev/null +++ b/M1/get_circle_area.cpp @@ -0,0 +1,32 @@ +#include "get_circle_area.hpp" + +#include +#include + +#include "point.hpp" + +namespace { + bool isPointInCircle(geom::Point pnt, unsigned radius) noexcept + { + double dx = pnt.x - radius; + double dy = pnt.y - radius; + + return dx * dx + dy * dy <= radius * radius; + } +} + +double circle::getCircleAreaMonteCarlo(int& error, unsigned radius, + const std::vector< geom::Point >& points) noexcept +{ + if (radius == 0 || points.empty()) { + error = 1; + + return 0.0; + } + + auto pntsInPred = std::bind(isPointInCircle, std::placeholders::_1, radius); + double pntsInCircle = std::count_if(points.cbegin(), points.cend(), pntsInPred); + error = 0; + + return (4.0 * radius * radius) * (pntsInCircle / points.size()); +} diff --git a/M1/get_circle_area.hpp b/M1/get_circle_area.hpp new file mode 100644 index 0000000..1e3101f --- /dev/null +++ b/M1/get_circle_area.hpp @@ -0,0 +1,12 @@ +#ifndef M1_GET_CIRCLE_AREA_HPP +#define M1_GET_CIRCLE_ARE_HPP + +#include + +#include "point.hpp" + +namespace circle { + double getCircleAreaMonteCarlo(int& error, unsigned radius, const std::vector< geom::Point >& points) noexcept; +} + +#endif diff --git a/M1/main.cpp b/M1/main.cpp index 0c87b37..d646f10 100644 --- a/M1/main.cpp +++ b/M1/main.cpp @@ -1,2 +1,73 @@ -int main() -{} +#include +#include +#include +#include +#include + +#include "generate_points_in_square.hpp" +#include "get_circle_area.hpp" + +int main(int argc, char* argv[]) +{ + if (argc < 2 || argc > 3) { + std::cerr << "Invalid command line parameters number\n"; + + return 1; + } + if (std::strtol(argv[1], nullptr, 10) == 0 || argv[1][0] == '-') { + std::cerr << "Invalid tries value\n"; + + return 1; + } + if (argc == 3 && (std::strtol(argv[2], nullptr, 10) == 0 || argv[2][0] == '-')) { + std::cerr << "Invalid seeed value\n"; + + return 1; + } + + int tries = std::strtol(argv[1], nullptr, 10); + int seed = argc == 3 ? std::strtol(argv[2], nullptr, 10) : 0; + int radius = 0; + + while ((std::cin >> radius) && !std::cin.eof()) { + if (radius <= 0) { + std::cerr << "Radius is not a positive number\n"; + + return 2; + } + + std::vector< geom::Point > points; + + try { + rndm::generatePointsInSquare(radius, tries, seed, points); + } catch (const std::exception& e) { + std::cerr << e.what() << '\n'; + + return 2; + } + + int errCircleArea = 0; + + const auto start{std::chrono::high_resolution_clock::now()}; + double circleArea = circle::getCircleAreaMonteCarlo(errCircleArea, radius, points); + const auto finish{std::chrono::high_resolution_clock::now()}; + + if (errCircleArea != 0.0) { + std::cerr << "Failed to calculate circle area\n"; + + continue; + } + + const std::chrono::duration< double, std::milli > duration_ms = finish - start; + + std::cout << std::fixed << std::setprecision(3); + std::cout << duration_ms.count(); + std::cout << ' ' << circleArea << '\n'; + } + + if (!std::cin.eof()) { + std::cerr << "Invalid input\n"; + + return 2; + } +} diff --git a/M1/point.hpp b/M1/point.hpp new file mode 100644 index 0000000..74c0ce7 --- /dev/null +++ b/M1/point.hpp @@ -0,0 +1,11 @@ +#ifndef M1_POINT_HPP +#define M1_POINT_HPP + +namespace geom { + struct Point + { + double x, y; + }; +} + +#endif From 4cabebbf008e75a86bc0a77976d18b7d36445349 Mon Sep 17 00:00:00 2001 From: jambii1 Date: Sun, 2 Nov 2025 16:45:02 +0000 Subject: [PATCH 3/3] [M1] Add multithreading --- M1/clicker.cpp | 13 ++++++ M1/clicker.hpp | 19 ++++++++ M1/generate_points_in_square.cpp | 27 ----------- M1/generate_points_in_square.hpp | 12 ----- M1/geometry_utils.cpp | 47 +++++++++++++++++++ M1/geometry_utils.hpp | 19 ++++++++ M1/get_circle_area.cpp | 32 ------------- M1/get_circle_area.hpp | 12 ----- M1/main.cpp | 79 ++++++++++++++++++++++---------- M1/point.hpp | 11 ----- 10 files changed, 154 insertions(+), 117 deletions(-) create mode 100644 M1/clicker.cpp create mode 100644 M1/clicker.hpp delete mode 100644 M1/generate_points_in_square.cpp delete mode 100644 M1/generate_points_in_square.hpp create mode 100644 M1/geometry_utils.cpp create mode 100644 M1/geometry_utils.hpp delete mode 100644 M1/get_circle_area.cpp delete mode 100644 M1/get_circle_area.hpp delete mode 100644 M1/point.hpp diff --git a/M1/clicker.cpp b/M1/clicker.cpp new file mode 100644 index 0000000..19ce029 --- /dev/null +++ b/M1/clicker.cpp @@ -0,0 +1,13 @@ +#include "clicker.hpp" + +mas::Clicker::Clicker(): + start_(std::chrono::high_resolution_clock::now()) +{} + +double mas::Clicker::millisec() const +{ + auto t = std::chrono::high_resolution_clock::now(); + std::chrono::duration< double, std::milli > f = t - start_; + + return f.count(); +} diff --git a/M1/clicker.hpp b/M1/clicker.hpp new file mode 100644 index 0000000..3cf6cbb --- /dev/null +++ b/M1/clicker.hpp @@ -0,0 +1,19 @@ +#ifndef M1_CLICKER_HPP +#define M1_CLICKER_HPP + +#include + +namespace mas { + class Clicker + { + public: + Clicker(); + + double millisec() const; + + private: + std::chrono::time_point< std::chrono::high_resolution_clock > start_; + }; +} + +#endif diff --git a/M1/generate_points_in_square.cpp b/M1/generate_points_in_square.cpp deleted file mode 100644 index d393a2e..0000000 --- a/M1/generate_points_in_square.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "generate_points_in_square.hpp" - -#include -#include - -void rndm::generatePointsInSquare(unsigned radius, unsigned tries, unsigned seed, std::vector< geom::Point >& points) -{ - if (radius == 0 || tries == 0 || !points.empty()) { - throw std::invalid_argument("generatePointsInSquare: invalid arguments"); - - return; - } - - double minX = 0.0, maxX = 2.0 * radius; - double minY = 0.0, maxY = 2.0 * radius; - - std::mt19937 gen(seed); - std::uniform_real_distribution< double > distX(minX, maxX); - std::uniform_real_distribution< double > distY(minY, maxY); - - for (unsigned long i = 0ul; i != tries; ++i) { - double x = distX(gen); - double y = distY(gen); - - points.push_back({x, y}); - } -} diff --git a/M1/generate_points_in_square.hpp b/M1/generate_points_in_square.hpp deleted file mode 100644 index 3fa15ea..0000000 --- a/M1/generate_points_in_square.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef M1_GENERATE_POINTS_IN_SQUARE_HPP -#define M1_GENERATE_POINTS_IN_SQUARE_HPP - -#include - -#include "point.hpp" - -namespace rndm { - void generatePointsInSquare(unsigned radius, unsigned tries, unsigned seed, std::vector< geom::Point >& points); -} - -#endif diff --git a/M1/geometry_utils.cpp b/M1/geometry_utils.cpp new file mode 100644 index 0000000..6864792 --- /dev/null +++ b/M1/geometry_utils.cpp @@ -0,0 +1,47 @@ +#include "geometry_utils.hpp" + +#include +#include +#include +#include + +namespace { + bool isPointInCircle(mas::Point pnt, unsigned radius) noexcept + { + double dx = pnt.x - radius; + double dy = pnt.y - radius; + + return dx * dx + dy * dy <= radius * radius; + } +} + +int mas::getPointsNumInCircle(unsigned radius, points_c_it_t begin, points_c_it_t end) noexcept +{ + auto pntsInPred = std::bind(isPointInCircle, std::placeholders::_1, radius); + int pntsInCircle = std::count_if(begin, end, pntsInPred); + + return pntsInCircle; +} + +void mas::generatePointsInSquare(unsigned radius, unsigned tries, unsigned seed, std::vector< Point >& points) +{ + if (radius == 0 || tries == 0 || !points.empty()) { + throw std::invalid_argument("generatePointsInSquare: invalid arguments"); + + return; + } + + double minX = 0.0, maxX = 2.0 * radius; + double minY = 0.0, maxY = 2.0 * radius; + + std::mt19937 gen(seed); + std::uniform_real_distribution< double > distX(minX, maxX); + std::uniform_real_distribution< double > distY(minY, maxY); + + for (unsigned long i = 0ul; i != tries; ++i) { + double x = distX(gen); + double y = distY(gen); + + points.push_back({x, y}); + } +} diff --git a/M1/geometry_utils.hpp b/M1/geometry_utils.hpp new file mode 100644 index 0000000..fbe8140 --- /dev/null +++ b/M1/geometry_utils.hpp @@ -0,0 +1,19 @@ +#ifndef M1_GEOMETRY_UTILS_HPP +#define M1_GEOMETRY_UTILS_HPP + +#include + +namespace mas { + struct Point + { + double x, y; + }; + + using points_c_it_t = std::vector< Point >::const_iterator; + + int getPointsNumInCircle(unsigned radius, points_c_it_t begin, points_c_it_t end) noexcept; + void generatePointsInSquare(unsigned radius, unsigned tries, unsigned seed, std::vector< Point >& points); + +} + +#endif diff --git a/M1/get_circle_area.cpp b/M1/get_circle_area.cpp deleted file mode 100644 index 868634d..0000000 --- a/M1/get_circle_area.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "get_circle_area.hpp" - -#include -#include - -#include "point.hpp" - -namespace { - bool isPointInCircle(geom::Point pnt, unsigned radius) noexcept - { - double dx = pnt.x - radius; - double dy = pnt.y - radius; - - return dx * dx + dy * dy <= radius * radius; - } -} - -double circle::getCircleAreaMonteCarlo(int& error, unsigned radius, - const std::vector< geom::Point >& points) noexcept -{ - if (radius == 0 || points.empty()) { - error = 1; - - return 0.0; - } - - auto pntsInPred = std::bind(isPointInCircle, std::placeholders::_1, radius); - double pntsInCircle = std::count_if(points.cbegin(), points.cend(), pntsInPred); - error = 0; - - return (4.0 * radius * radius) * (pntsInCircle / points.size()); -} diff --git a/M1/get_circle_area.hpp b/M1/get_circle_area.hpp deleted file mode 100644 index 1e3101f..0000000 --- a/M1/get_circle_area.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef M1_GET_CIRCLE_AREA_HPP -#define M1_GET_CIRCLE_ARE_HPP - -#include - -#include "point.hpp" - -namespace circle { - double getCircleAreaMonteCarlo(int& error, unsigned radius, const std::vector< geom::Point >& points) noexcept; -} - -#endif diff --git a/M1/main.cpp b/M1/main.cpp index d646f10..050e69e 100644 --- a/M1/main.cpp +++ b/M1/main.cpp @@ -1,11 +1,22 @@ +#include +#include #include #include #include #include -#include +#include -#include "generate_points_in_square.hpp" -#include "get_circle_area.hpp" +#include "clicker.hpp" +#include "geometry_utils.hpp" + +namespace { + using seg_it_t = std::vector< double >::iterator; + + void getPointsNumInCircleSegment(unsigned radius, mas::points_c_it_t begin, mas::points_c_it_t end, seg_it_t result) + { + *result = mas::getPointsNumInCircle(radius, begin, end); + } +} int main(int argc, char* argv[]) { @@ -25,44 +36,66 @@ int main(int argc, char* argv[]) return 1; } + using namespace mas; + int tries = std::strtol(argv[1], nullptr, 10); int seed = argc == 3 ? std::strtol(argv[2], nullptr, 10) : 0; int radius = 0; + int threadNum = 0; - while ((std::cin >> radius) && !std::cin.eof()) { - if (radius <= 0) { - std::cerr << "Radius is not a positive number\n"; + while ((std::cin >> radius >> threadNum) && !std::cin.eof()) { + if (radius <= 0 || threadNum <= 0) { + std::cerr << "Radius or thread number is not a positive number\n"; return 2; } - std::vector< geom::Point > points; - + std::vector< mas::Point > points; try { - rndm::generatePointsInSquare(radius, tries, seed, points); + mas::generatePointsInSquare(radius, tries, seed, points); } catch (const std::exception& e) { std::cerr << e.what() << '\n'; return 2; } - int errCircleArea = 0; - - const auto start{std::chrono::high_resolution_clock::now()}; - double circleArea = circle::getCircleAreaMonteCarlo(errCircleArea, radius, points); - const auto finish{std::chrono::high_resolution_clock::now()}; - - if (errCircleArea != 0.0) { - std::cerr << "Failed to calculate circle area\n"; - - continue; + double duration_ms = 0.0; + int pointsNumInCircle = 0; + { + try { + std::vector< std::thread > threads; + threads.reserve(threadNum); + std::vector< double > results(threadNum, 0); + mas::Clicker cl; + + size_t per_th = points.size() / threadNum; + int i = 0; + auto it = points.cbegin(); + for (; i < threadNum - 1; ++i) { + auto end = it + per_th; + threads.emplace_back(getPointsNumInCircleSegment, radius, it, end, results.begin() + i); + it = end; + } + getPointsNumInCircleSegment(radius, it, it + per_th + points.size() % threadNum, results.begin() + i); + for (auto&& thread: threads) { + thread.join(); + } + + pointsNumInCircle = std::accumulate(results.cbegin(), results.cend(), 0); + duration_ms = cl.millisec(); + } catch (std::bad_alloc& e) { + std::cerr << e.what() << '\n'; + + return 2; + } } - const std::chrono::duration< double, std::milli > duration_ms = finish - start; - std::cout << std::fixed << std::setprecision(3); - std::cout << duration_ms.count(); - std::cout << ' ' << circleArea << '\n'; + std::cout << duration_ms << ' '; + + double circleArea = + (4.0 * radius * radius) * (static_cast< double >(pointsNumInCircle) / static_cast< double >(points.size())); + std::cout << circleArea << '\n'; } if (!std::cin.eof()) { diff --git a/M1/point.hpp b/M1/point.hpp deleted file mode 100644 index 74c0ce7..0000000 --- a/M1/point.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef M1_POINT_HPP -#define M1_POINT_HPP - -namespace geom { - struct Point - { - double x, y; - }; -} - -#endif