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/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/main.cpp b/M1/main.cpp new file mode 100644 index 0000000..050e69e --- /dev/null +++ b/M1/main.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include +#include + +#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[]) +{ + 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; + } + + 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 >> 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< mas::Point > points; + try { + mas::generatePointsInSquare(radius, tries, seed, points); + } catch (const std::exception& e) { + std::cerr << e.what() << '\n'; + + return 2; + } + + 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; + } + } + + std::cout << std::fixed << std::setprecision(3); + 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()) { + std::cerr << "Invalid input\n"; + + return 2; + } +}