diff --git a/.gitignore b/.gitignore index 3c4efe2..8d473e3 100644 --- a/.gitignore +++ b/.gitignore @@ -258,4 +258,18 @@ paket-files/ # Python Tools for Visual Studio (PTVS) __pycache__/ -*.pyc \ No newline at end of file +*.pyc + +# CMake build artifacts +build/ +CMakeCache.txt +CMakeFiles/ +*.cmake +Makefile +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +# Dependency files +*.d \ No newline at end of file diff --git a/ApplicationController.cpp b/ApplicationController.cpp deleted file mode 100644 index f0302f0..0000000 --- a/ApplicationController.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "ApplicationController.h" - -ApplicationController::ApplicationController() - : console{ ConsoleManager::get_console_manager() }, approximator{ ApproximationController::get_approximation_controller() } -{ -} - -ApplicationController& ApplicationController::get_application_controller() -{ - static ApplicationController app_controller; - return app_controller; -} - -void ApplicationController::run_app() const -{ - int option{ console.show_menu(approximator.get_names()) }; - while (option > 0) - { - const int n{ console.get_accuracy() }; - if (option > approximator.implemented_algorithms_count()) - { - console.show_error("Niepoprawny wybor"); - return; - } - const double result{ approximator.approximate_pi(n, option-1) }; - console.update_result(result); - option = console.show_menu(approximator.get_names()); - } -} \ No newline at end of file diff --git a/ApplicationController.h b/ApplicationController.h deleted file mode 100644 index 0c03817..0000000 --- a/ApplicationController.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "ConsoleManager.h" -#include "ApproximationController.h" - -/** - Klasa gwna, sterujca programem. Implementuje wzorzec projektowy singleton. -*/ -class ApplicationController -{ - ApplicationController(); - ApplicationController(ApplicationController&&) = delete; - ApplicationController(const ApplicationController&) = delete; - - ConsoleManager& console; // Obiekt klasy zarzdzajcej konsol (wyjciem) - ApproximationController& approximator; // Obiekt klasy dysponujcej zbiorem algorytmw przybliajcych liczb pi -public: - static ApplicationController& get_application_controller(); - void run_app() const; // Metoda kontrolujca przebieg programu -}; \ No newline at end of file diff --git a/Approximating-Pi.sln b/Approximating-Pi.sln deleted file mode 100644 index ed737f7..0000000 --- a/Approximating-Pi.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.438 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Approximating-Pi", "Approximating-Pi.vcxproj", "{61C7D84C-67AD-4E27-BEF4-047C5CDBB89D}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {61C7D84C-67AD-4E27-BEF4-047C5CDBB89D}.Debug|x64.ActiveCfg = Debug|x64 - {61C7D84C-67AD-4E27-BEF4-047C5CDBB89D}.Debug|x64.Build.0 = Debug|x64 - {61C7D84C-67AD-4E27-BEF4-047C5CDBB89D}.Debug|x86.ActiveCfg = Debug|Win32 - {61C7D84C-67AD-4E27-BEF4-047C5CDBB89D}.Debug|x86.Build.0 = Debug|Win32 - {61C7D84C-67AD-4E27-BEF4-047C5CDBB89D}.Release|x64.ActiveCfg = Release|x64 - {61C7D84C-67AD-4E27-BEF4-047C5CDBB89D}.Release|x64.Build.0 = Release|x64 - {61C7D84C-67AD-4E27-BEF4-047C5CDBB89D}.Release|x86.ActiveCfg = Release|Win32 - {61C7D84C-67AD-4E27-BEF4-047C5CDBB89D}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {ED2B4AB8-4D52-47F7-AA4E-B575B0EDEEED} - EndGlobalSection -EndGlobal diff --git a/Approximating-Pi.vcxproj b/Approximating-Pi.vcxproj deleted file mode 100644 index 24725c1..0000000 --- a/Approximating-Pi.vcxproj +++ /dev/null @@ -1,147 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {61C7D84C-67AD-4E27-BEF4-047C5CDBB89D} - ApproximatingPi - 10.0.16299.0 - - - - Application - true - v141 - MultiByte - - - Application - false - v141 - true - MultiByte - - - Application - true - v141 - MultiByte - - - Application - false - v141 - true - MultiByte - - - - - - - - - - - - - - - - - - - - - - - Level3 - Disabled - true - true - - - - - Level3 - Disabled - true - true - - - - - Level3 - MaxSpeed - true - true - true - true - - - true - true - - - - - Level3 - MaxSpeed - true - true - true - true - - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Approximating-Pi.vcxproj.filters b/Approximating-Pi.vcxproj.filters deleted file mode 100644 index 2677b96..0000000 --- a/Approximating-Pi.vcxproj.filters +++ /dev/null @@ -1,92 +0,0 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {0b1b4203-6a82-4935-8979-2fd9544f8c3e} - - - {d0476da4-9c02-488a-aba8-32eb7066e6c1} - - - - - Pliki źródłowe - - - Pliki źródłowe - - - Pliki źródłowe - - - Pliki źródłowe - - - Pliki nagłówkowe\Approximating Algorithms\Implementations - - - Pliki nagłówkowe\Approximating Algorithms\Implementations - - - Pliki nagłówkowe\Approximating Algorithms\Implementations - - - Pliki nagłówkowe\Approximating Algorithms\Implementations - - - Pliki nagłówkowe\Approximating Algorithms\Implementations - - - Pliki nagłówkowe\Approximating Algorithms\Implementations - - - Pliki nagłówkowe\Approximating Algorithms\Implementations - - - - - Pliki nagłówkowe - - - Pliki nagłówkowe - - - Pliki nagłówkowe - - - Pliki nagłówkowe - - - Pliki nagłówkowe\Approximating Algorithms - - - Pliki nagłówkowe\Approximating Algorithms - - - Pliki nagłówkowe\Approximating Algorithms - - - Pliki nagłówkowe\Approximating Algorithms - - - Pliki nagłówkowe\Approximating Algorithms - - - Pliki nagłówkowe\Approximating Algorithms - - - Pliki nagłówkowe\Approximating Algorithms - - - Pliki nagłówkowe\Approximating Algorithms - - - \ No newline at end of file diff --git a/ApproximationController.cpp b/ApproximationController.cpp deleted file mode 100644 index c07d48d..0000000 --- a/ApproximationController.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "ApproximationController.h" -#include "BaselProblemApproximatingAlgorithm.h" -#include "FactorialApproximatingAlgorithm.h" -#include "MonteCarloApproximatingAlgorithm.h" -#include "IntegrationApproximatingAlgorithm.h" -#include "WallisProductApproximatingAlgorithm.h" -#include "LeibnizFormulaApproximatingAlgorithm.h" -#include "HalfCircleAreaIntegrationApproximatingAlgorithm.h" - -ApproximationController::ApproximationController() -{ - algorithms.emplace_back(new BaselProblemApproximatingAlgorithm()); - algorithms.emplace_back(new FactorialApproximatingAlgorithm()); - algorithms.emplace_back(new MonteCarloApproximatingAlgorithm()); - algorithms.emplace_back(new IntegrationApproximatingAlgorithm()); - algorithms.emplace_back(new WallisProductApproximatingAlgorithm()); - algorithms.emplace_back(new LeibnizFormulaApproximatingAlgorithm()); - algorithms.emplace_back(new HalfCircleAreaIntegrationApproximatingAlgorithm()); -} - -double ApproximationController::approximate_pi(int accuracy_level, int algorithm) const -{ - return (*algorithms[static_cast(algorithm)])(accuracy_level); -} -int ApproximationController::implemented_algorithms_count() const -{ - return algorithms.size(); -} - -ApproximationController & ApproximationController::get_approximation_controller() -{ - static ApproximationController approximating_algorithm; - return approximating_algorithm; -} - -std::vector ApproximationController::get_names() -{ - std::vector result; - for (ApproxAlgoPtr& ptr : algorithms) - result.push_back(ptr->get_name()); - return result; -} \ No newline at end of file diff --git a/ApproximationController.h b/ApproximationController.h deleted file mode 100644 index a685d92..0000000 --- a/ApproximationController.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include -#include -#include "IApproximatingAlgorithm.h" - -/** - Manager algorytmw aproksymujcych, wywouje odpowiednie algorytmy szacujce warto liczby pi i zwraca wynik. - Klasa jest cakowicie niezalena od wyjcia. -*/ -class ApproximationController -{ - using ApproxAlgoPtr = std::unique_ptr; - - std::vector algorithms; // Wektor zawierajcy wskaniki na odpowiednie algorytmy - ApproximationController(); - ApproximationController(ApproximationController&&) = delete; - ApproximationController(const ApproximationController&) = delete; - -public: - double approximate_pi(int accuracy_level, int algorithm = 1) const; - int implemented_algorithms_count() const; // Funkcja zwracajca ilo aktualnie zaimplementowanych algorytmw, tj. rozmiar wektora algorithms - std::vector get_names(); // Funkcja zwracajca nazwy wszystkich algorytmw, wykorzystywana do poprawnego wywietlania menu - static ApproximationController& get_approximation_controller(); // Implementacja wzorca projektowego singleton -}; \ No newline at end of file diff --git a/BaselProblemApproximatingAlgorithm.cpp b/BaselProblemApproximatingAlgorithm.cpp deleted file mode 100644 index 1eebda1..0000000 --- a/BaselProblemApproximatingAlgorithm.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "BaselProblemApproximatingAlgorithm.h" - -double BaselProblemApproximatingAlgorithm::approximate_pi(int accuracy_level) const -{ - double sum{ 0.0 }; - for (int i{ 1 }; i <= accuracy_level; i++) - sum += 1.0 / (i*i); - return std::sqrt(6 * sum); -} \ No newline at end of file diff --git a/BaselProblemApproximatingAlgorithm.h b/BaselProblemApproximatingAlgorithm.h deleted file mode 100644 index 5aa5b59..0000000 --- a/BaselProblemApproximatingAlgorithm.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "IApproximatingAlgorithm.h" -#include - -/** - Algorytm obliczajcy przyblion warto liczby pi za pomoc tosamoci odkrytej przez Eulera - znanej jako problem bazylejski - \frac{\pi^2}{6} = \sum_{n=0}^{\infty} -*/ -class BaselProblemApproximatingAlgorithm : - public IApproximatingAlgorithm -{ -public: - inline virtual std::string get_name() const { return "Aproksymacja liczby pi za pomoca sumy odwrotnosci kwadratow kolejnych liczb naturalnych"; } - virtual double approximate_pi(int accuracy_level) const; -}; \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..681c3c8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,101 @@ +cmake_minimum_required(VERSION 3.16) +project(approximatingPi + VERSION 1.0.0 + DESCRIPTION "Pi approximation algorithms using various mathematical methods" + LANGUAGES CXX +) +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +if(MSVC) + add_compile_options(/W4 /WX) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) + if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_compile_options(/O2) + endif() +else() + add_compile_options(-Wall -Wextra -Wpedantic -Werror) + if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_compile_options(-O3) + endif() +endif() +set(CORE_HEADER_FILES + include/approximating-pi/core/IAlgorithm.hpp + include/approximating-pi/core/ApplicationController.hpp + include/approximating-pi/core/ApproximationController.hpp + include/approximating-pi/core/ConsoleManager.hpp + include/approximating-pi/core/IntegralUtilities.hpp +) +set(CORE_SOURCE_FILES + src/approximating-pi/core/ApplicationController.cpp + src/approximating-pi/core/ApproximationController.cpp + src/approximating-pi/core/ConsoleManager.cpp +) +set(ALGORITHM_HEADER_FILES + include/approximating-pi/algorithms/BaselProblem.hpp + include/approximating-pi/algorithms/Factorial.hpp + include/approximating-pi/algorithms/HalfCircleAreaIntegration.hpp + include/approximating-pi/algorithms/Integration.hpp + include/approximating-pi/algorithms/LeibnizFormula.hpp + include/approximating-pi/algorithms/MonteCarlo.hpp + include/approximating-pi/algorithms/WallisProduct.hpp +) +set(ALGORITHM_SOURCE_FILES + src/approximating-pi/algorithms/BaselProblem.cpp + src/approximating-pi/algorithms/Factorial.cpp + src/approximating-pi/algorithms/HalfCircleAreaIntegration.cpp + src/approximating-pi/algorithms/Integration.cpp + src/approximating-pi/algorithms/LeibnizFormula.cpp + src/approximating-pi/algorithms/MonteCarlo.cpp + src/approximating-pi/algorithms/WallisProduct.cpp +) +add_library(piApproximation STATIC + ${CORE_SOURCE_FILES} + ${ALGORITHM_SOURCE_FILES} +) +target_include_directories(piApproximation + PUBLIC + ${CMAKE_SOURCE_DIR}/include +) +add_executable(${PROJECT_NAME} + main.cpp +) +target_link_libraries(${PROJECT_NAME} + PRIVATE + piApproximation +) +if(UNIX AND NOT APPLE) + target_link_libraries(${PROJECT_NAME} PRIVATE pthread) +endif() +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_SOURCE_DIR}/include +) +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + if(MSVC) + target_compile_options(${PROJECT_NAME} PRIVATE /Od /Zi) + else() + target_compile_options(${PROJECT_NAME} PRIVATE -O0 -g) + endif() +endif() +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION bin + COMPONENT applications +) +install(FILES ${CORE_HEADER_FILES} ${ALGORITHM_HEADER_FILES} + DESTINATION include/approximating-pi + COMPONENT development +) +add_subdirectory(tests) + +include(CPack) +set(CPACK_PACKAGE_NAME "approximatingPi") +set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_DESCRIPTION}) +set(CPACK_PACKAGE_VENDOR "Pi Approximation Project") +if(WIN32) + set(CPACK_GENERATOR "ZIP;NSIS") +else() + set(CPACK_GENERATOR "TGZ;DEB") +endif() \ No newline at end of file diff --git a/ConsoleManager.cpp b/ConsoleManager.cpp deleted file mode 100644 index 4bd3d61..0000000 --- a/ConsoleManager.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "ConsoleManager.h" - -ConsoleManager& ConsoleManager::get_console_manager() -{ - static ConsoleManager console_manager; - return console_manager; -} - -int ConsoleManager::show_menu(std::vector algorithm_names) const -{ - int option{ 0 }; - std::cout << "0. Wyjscie z programu\n"; - for (int i = 1; i <= algorithm_names.size(); i++) - std::cout << i << ". " << algorithm_names[i-1] << "\n"; - std::cout << "Wybor: "; - std::cin >> option; - while(!std::cin.good() || option < 0) - { - std::cout << "Cos poszlo nie tak... Prawdopodobnie wprowadziles niepoprawna wartosc. Sprobuj ponownie.\nWybor: "; - std::cin.clear(); - std::cin.ignore(123,static_cast('\n')); - std::cin >> option; - } - return option; -} - -int ConsoleManager::get_accuracy() const -{ - int accuracy; - std::cout << "Wprowadz liczbe calkowita - stopien dokladnosci obliczen: "; - std::cin >> accuracy; - while (!std::cin.good() || accuracy < 0) - { - std::cout << "Cos poszlo nie tak... Prawdopodobnie wprowadziles niepoprawna wartosc. Sprobuj ponownie.\nWybor: "; - std::cin.clear(); - std::cin.ignore(123, static_cast('\n')); - std::cin >> accuracy; - } - return accuracy; -} - -void ConsoleManager::show_error(const std::string & error_info) const -{ - using namespace std::chrono_literals; - std::cout << "Wystapil blad!\nSzczegolowe informacje: " << error_info << "\n\nProgram zostanie za chwile zamkniety\n"; - std::this_thread::sleep_for(5s); - -} - -void ConsoleManager::update_result(double result) const -{ - using namespace std::chrono_literals; - std::cout << "Wynik obliczen: " << result << "\n"; - std::this_thread::sleep_for(3s); -} \ No newline at end of file diff --git a/ConsoleManager.h b/ConsoleManager.h deleted file mode 100644 index 9c27660..0000000 --- a/ConsoleManager.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -/** - Klasa zarzdajca konsol. -*/ -class ConsoleManager -{ -private: - ConsoleManager() = default; - ConsoleManager(const ConsoleManager&) = delete; - ConsoleManager(ConsoleManager&&) = delete; - -public: - static ConsoleManager& get_console_manager(); - int show_menu(std::vector algorithm_names) const; // Funkcja pokazujca menu, zwraca wybran przez uytkownika opcj. - int get_accuracy() const; // Funkcja wywietlajca monit o ustalenie dokadnoci oblicze, zwraca liczb naturaln - stopie dokadnoci, np. ilo wyrazw szeregu do zsumowania. - void show_error(const std::string & error_info) const; // Wywietla komunikat bdu. - void update_result(double result) const; // Wywietla wynik oblicze. -}; \ No newline at end of file diff --git a/FactorialApproximatingAlgorithm.cpp b/FactorialApproximatingAlgorithm.cpp deleted file mode 100644 index e6d2630..0000000 --- a/FactorialApproximatingAlgorithm.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "FactorialApproximatingAlgorithm.h" - -double FactorialApproximatingAlgorithm::factorial(int n) const -{ - double result{ 1.0 }; - for (int i = 2; i <= n; i ++) - { - result *= static_cast(i); - } - return result; -} - -double FactorialApproximatingAlgorithm::double_factorial(int n) const -{ - double result{ 1.0 }; - for (int i = (n % 2 == 0 ? 2 : 1); i <= n; i+=2) - { - result *= static_cast(i); - } - return result; -} - -double FactorialApproximatingAlgorithm::approximate_pi(int accuracy_level) const -{ - double sum{ 0.0 }; - for(int i{ 0 }; i < accuracy_level; i++) - { - sum += factorial(i) / double_factorial(2 * i + 1); - } - return sum * 2; -} diff --git a/FactorialApproximatingAlgorithm.h b/FactorialApproximatingAlgorithm.h deleted file mode 100644 index 88ea96f..0000000 --- a/FactorialApproximatingAlgorithm.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "IApproximatingAlgorithm.h" -/** - Klasa realizujca wyznaczanie liczby pi poprzez tosamo: \pi ~ \sum_{n=0}^{\infty} \frac{n!}{(2n+1)!!} -*/ -class FactorialApproximatingAlgorithm : - public IApproximatingAlgorithm -{ - double factorial(int n) const; - double double_factorial(int n) const; - -public: - inline virtual std::string get_name() const { return "Aproksymacja liczby pi za pomoca tozsamosci zwiazanej z silnia i podwojna silnia"; } - virtual double approximate_pi(int accuracy_level) const; -}; \ No newline at end of file diff --git a/HalfCircleAreaIntegrationApproximatingAlgorithm.cpp b/HalfCircleAreaIntegrationApproximatingAlgorithm.cpp deleted file mode 100644 index 494855c..0000000 --- a/HalfCircleAreaIntegrationApproximatingAlgorithm.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "HalfCircleAreaIntegrationApproximatingAlgorithm.h" -#include "IntegralUtilities.h" - -double HalfCircleAreaIntegrationApproximatingAlgorithm::approximate_pi(int accuracy_level) const -{ - return 2.0*IntegralUtilities::just_integrate(-1, 1, accuracy_level, [](double x) { return std::sqrt(1 - std::pow(x, 2)); }); -} diff --git a/HalfCircleAreaIntegrationApproximatingAlgorithm.h b/HalfCircleAreaIntegrationApproximatingAlgorithm.h deleted file mode 100644 index 97c770c..0000000 --- a/HalfCircleAreaIntegrationApproximatingAlgorithm.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "IApproximatingAlgorithm.h" -/** - Klasa wyznaczajca przyblion warto liczby pi poprzez obliczenie pola pokrgu i wyznaczenie z niego liczby pi. - Pole pokrgu jest realizowane jako warto caki z funkcji sqrt(1-x^2) na przedziale [-1,1]. - Klasa korzysta z IntegralUtilities. -*/ -class HalfCircleAreaIntegrationApproximatingAlgorithm : - public IApproximatingAlgorithm -{ -public: - inline virtual std::string get_name() const { return "Numeryczne obliczenie pola polkola (jako wykresu funkcji sqrt(1-x^2) i wyznaczenie liczby pi"; } - virtual double approximate_pi(int accuracy_level) const; -}; \ No newline at end of file diff --git a/IApproximatingAlgorithm.h b/IApproximatingAlgorithm.h deleted file mode 100644 index d7582cf..0000000 --- a/IApproximatingAlgorithm.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include - -/** - Interfejs ujednolicajcy wszystkie algorytmy. -*/ -class IApproximatingAlgorithm -{ -public: - virtual ~IApproximatingAlgorithm() = default; // Polimorfizm itp - - virtual double approximate_pi(int accuracy_level) const = 0; // Waciwa metoda suca do obliczania wartoci liczby pi - inline virtual std::string get_name() const = 0; // Metoda zwracajca nazw danego algorytmu - virtual double operator()(int accuracy_level) const - { - return approximate_pi(accuracy_level); - } -}; \ No newline at end of file diff --git a/IntegralUtilities.h b/IntegralUtilities.h deleted file mode 100644 index a519436..0000000 --- a/IntegralUtilities.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include - -/** - Klasa (cho rwnie dobrze mogaby by to przestrze nazw, w praktyce ni wanie jest) - zawierajca metody cakowania. Aktualny projekt wymaga tylko jakiejkolwiek caki, - ale niewykluczone jest, e w przyszoci zostanie rozszerzona o peen wachlarz - moliwoci cakowania, np. funkcj liczc sum grn/doln dla zadanego podziau, - czy po prostu funkcj realizujc np. metod Simpsona z zadanymi parametrami. -*/ -class IntegralUtilities -{ -public: - /** - Jako, e obecny projekt nie skupia si na cakowaniu i potrzebuje jakiegokolwiek cakowania, to - funkcja cakujca po prostu ma cakowa. - */ - template - static double just_integrate(const FunctionArgumentType& a, const FunctionArgumentType& b, int accuracy_level, const std::function& f) - { - double sum{ 0.0 }; - double dx{ (b - a) / static_cast(accuracy_level) }; - FunctionArgumentType x{ a }; - for (int i{ 0 }; i < accuracy_level; i++) - { - sum += dx * static_cast(f(x)); - x += dx; - } - return sum; - } -}; \ No newline at end of file diff --git a/IntegrationApproximatingAlgorithm.cpp b/IntegrationApproximatingAlgorithm.cpp deleted file mode 100644 index 3647fc0..0000000 --- a/IntegrationApproximatingAlgorithm.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "IntegrationApproximatingAlgorithm.h" -#include "IntegralUtilities.h" -#include - -double IntegrationApproximatingAlgorithm::approximate_pi(int accuracy_level) const -{ - return IntegralUtilities::just_integrate(0.0, 1.0, accuracy_level, [](double x) {return 4.0 / (1.0 + x * x); }); -} diff --git a/IntegrationApproximatingAlgorithm.h b/IntegrationApproximatingAlgorithm.h deleted file mode 100644 index 688e051..0000000 --- a/IntegrationApproximatingAlgorithm.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "IApproximatingAlgorithm.h" - -/** - Klasa obliczajca warto liczby pi poprzez cak z 4/(1+x^2) na przedziale [0,1], tj. korzystajca - z tosamoci arctg(1) = pi/4 i wykorzystujca numeryczn warto tej caki. - Klasa korzysta z IntegralUtilities. -*/ -class IntegrationApproximatingAlgorithm : - public IApproximatingAlgorithm -{ -public: - inline virtual std::string get_name() const { return "Przyblizenie liczby pi poprzez tozsamosc pi/4 = arctg(1) = calka z 1/(1+x^2) na przedziale [0,1] poprzez numeryczne obliczenie calki"; } - virtual double approximate_pi(int accuracy_level) const; -}; - diff --git a/LeibnizFormulaApproximatingAlgorithm.cpp b/LeibnizFormulaApproximatingAlgorithm.cpp deleted file mode 100644 index b337555..0000000 --- a/LeibnizFormulaApproximatingAlgorithm.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "LeibnizFormulaApproximatingAlgorithm.h" -#include - -double LeibnizFormulaApproximatingAlgorithm::approximate_pi(int accuracy_level) const -{ - double sum{ 0.0 }; - for (int i{ 0 }; i < accuracy_level; i++) - { - sum += std::pow(-1.0, i) / (2.0*i + 1.0); - } - return 4.0 * sum; -} \ No newline at end of file diff --git a/LeibnizFormulaApproximatingAlgorithm.h b/LeibnizFormulaApproximatingAlgorithm.h deleted file mode 100644 index db02953..0000000 --- a/LeibnizFormulaApproximatingAlgorithm.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "IApproximatingAlgorithm.h" - -/** - Klasa wyznaczajca warto liczby pi za pomoc wzoru Leibniza: \sum_{n=0}^{\infty} \frac{(-1)^n}{2n+1} -*/ -class LeibnizFormulaApproximatingAlgorithm - : public IApproximatingAlgorithm -{ -public: - inline virtual std::string get_name() const { return "Estymacja liczby pi za pomoca wzoru Leibniza (wzoru MadhavaLeibniza): suma (-1)^n/(2n+1)"; } - virtual double approximate_pi(int accuracy_level) const; -}; \ No newline at end of file diff --git a/MonteCarloApproximatingAlgorithm.cpp b/MonteCarloApproximatingAlgorithm.cpp deleted file mode 100644 index 51a64e5..0000000 --- a/MonteCarloApproximatingAlgorithm.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "MonteCarloApproximatingAlgorithm.h" - -double MonteCarloApproximatingAlgorithm::approximate_pi(int accuracy_level) const -{ - std::default_random_engine random_engine; - std::uniform_real_distribution distribution; - const int n{ accuracy_level * 150 }; - double x, y; - int points_in_circle{ 0 }; - for (int i{ 0 }; i < n; i++) - { - x = distribution(random_engine); - y = distribution(random_engine); - if (x*x + y * y <= 1) - points_in_circle++; - } - return 4.0 * points_in_circle / (accuracy_level * 150.0); -} diff --git a/MonteCarloApproximatingAlgorithm.h b/MonteCarloApproximatingAlgorithm.h deleted file mode 100644 index 616aadd..0000000 --- a/MonteCarloApproximatingAlgorithm.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "IApproximatingAlgorithm.h" -#include - -/** - Klasa obliczajca przyblion warto liczby pi poprzez wylosowanie pewnej iloci punktw z kwadratu - i sprawdzenie ile z tych punktw naley do okrgu wpisanego w w kwadrat. -*/ -class MonteCarloApproximatingAlgorithm : - public IApproximatingAlgorithm -{ -public: - inline virtual std::string get_name() const { return "Przyblizone obliczenie liczby pi poprzez zastosowanie metody Monte-Carlo"; } - virtual double approximate_pi(int accuracy_level) const; // ilo punktw = accuracy_level * 150 -}; \ No newline at end of file diff --git a/WallisProductApproximatingAlgorithm.cpp b/WallisProductApproximatingAlgorithm.cpp deleted file mode 100644 index e61f1e0..0000000 --- a/WallisProductApproximatingAlgorithm.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "WallisProductApproximatingAlgorithm.h" - -double WallisProductApproximatingAlgorithm::approximate_pi(int accuracy_level) const -{ - double product_value{ 1.0 }, up{ 2.0 }, denominator{ 1.0 }; - for (int i{ 0 }; i < accuracy_level; i+=1) - { - product_value *= up / denominator; - if (i % 2 == 0) - denominator += 2; - else up += 2; - } - return 2.0*product_value; -} diff --git a/WallisProductApproximatingAlgorithm.h b/WallisProductApproximatingAlgorithm.h deleted file mode 100644 index 9854b5c..0000000 --- a/WallisProductApproximatingAlgorithm.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "IApproximatingAlgorithm.h" - -/** - Klasa wykorzystujca wzr Wallisa do oszacowania wartoci liczby pi. -*/ -class WallisProductApproximatingAlgorithm : - public IApproximatingAlgorithm -{ -public: - inline virtual std::string get_name() const { return "Wykorzystanie wzoru Wallisa do oszacowania wartosci pi"; } - virtual double approximate_pi(int accuracy_level) const; -}; \ No newline at end of file diff --git a/include/approximating-pi/algorithms/BaselProblem.hpp b/include/approximating-pi/algorithms/BaselProblem.hpp new file mode 100644 index 0000000..aac041c --- /dev/null +++ b/include/approximating-pi/algorithms/BaselProblem.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "../core/IAlgorithm.hpp" +#include +#include + +namespace approximation { +namespace algorithms { + +class BaselProblem : public IAlgorithm { +public: + inline std::string getDescription() const override { + return "Approximation of pi using the sum of reciprocals of squares of " + "consecutive natural numbers"; + } + double approximatePi(int accuracyLevel) const override; + inline std::string getName() const override { return "Basel"; } +}; + +} // namespace algorithms +} // namespace approximation \ No newline at end of file diff --git a/include/approximating-pi/algorithms/Factorial.hpp b/include/approximating-pi/algorithms/Factorial.hpp new file mode 100644 index 0000000..c0b30d2 --- /dev/null +++ b/include/approximating-pi/algorithms/Factorial.hpp @@ -0,0 +1,21 @@ +#pragma once +#include "../core/IAlgorithm.hpp" + +namespace approximation { +namespace algorithms { + +class Factorial : public IAlgorithm { + double factorial(int n) const; + double doubleFactorial(int n) const; + +public: + inline std::string getDescription() const override { + return "Approximation of pi using identity related to factorial and double " + "factorial"; + } + double approximatePi(int accuracyLevel) const override; + inline std::string getName() const override { return "Factorial"; } +}; + +} // namespace algorithms +} // namespace approximation \ No newline at end of file diff --git a/include/approximating-pi/algorithms/HalfCircleAreaIntegration.hpp b/include/approximating-pi/algorithms/HalfCircleAreaIntegration.hpp new file mode 100644 index 0000000..0d2f7df --- /dev/null +++ b/include/approximating-pi/algorithms/HalfCircleAreaIntegration.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "../core/IAlgorithm.hpp" +#include + +namespace approximation { +namespace algorithms { + +class HalfCircleAreaIntegration : public IAlgorithm { +public: + inline std::string getDescription() const override { + return "Numerical calculation of the semicircle area (as the graph of " + "sqrt(1-x^2)) and determination of pi"; + } + double approximatePi(int accuracyLevel) const override; + inline std::string getName() const override { return "Half Circle"; } +}; + +} // namespace algorithms +} // namespace approximation \ No newline at end of file diff --git a/include/approximating-pi/algorithms/Integration.hpp b/include/approximating-pi/algorithms/Integration.hpp new file mode 100644 index 0000000..1977f30 --- /dev/null +++ b/include/approximating-pi/algorithms/Integration.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "../core/IAlgorithm.hpp" + +namespace approximation { +namespace algorithms { + +class Integration : public IAlgorithm { +public: + inline std::string getDescription() const override { + return "Approximation of pi using the identity pi/4 = arctan(1) = integral " + "of 1/(1+x^2) over [0,1] via numerical integration"; + } + double approximatePi(int accuracyLevel) const override; + + inline std::string getName() const override { return "Integration"; } +}; + +} // namespace algorithms +} // namespace approximation diff --git a/include/approximating-pi/algorithms/LeibnizFormula.hpp b/include/approximating-pi/algorithms/LeibnizFormula.hpp new file mode 100644 index 0000000..3fa682f --- /dev/null +++ b/include/approximating-pi/algorithms/LeibnizFormula.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "../core/IAlgorithm.hpp" + +namespace approximation { +namespace algorithms { + +class LeibnizFormula : public IAlgorithm { +public: + inline std::string getDescription() const override { + return "Pi approximation using Leibniz formula (Madhava-Leibniz series): " + "sum (-1)^n/(2n+1)"; + } + double approximatePi(int accuracyLevel) const override; + + inline std::string getName() const override { return "Leibniz"; } +}; + +} // namespace algorithms +} // namespace approximation \ No newline at end of file diff --git a/include/approximating-pi/algorithms/MonteCarlo.hpp b/include/approximating-pi/algorithms/MonteCarlo.hpp new file mode 100644 index 0000000..de4fbdd --- /dev/null +++ b/include/approximating-pi/algorithms/MonteCarlo.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "../core/IAlgorithm.hpp" +#include + +namespace approximation { +namespace algorithms { + +class MonteCarlo : public IAlgorithm { +public: + inline std::string getDescription() const override { + return "Monte Carlo method for pi approximation through random point " + "sampling"; + } + double approximatePi(int accuracyLevel) const override; + inline std::string getName() const override { return "Monte Carlo"; } + +private: + static constexpr int POINTS_MULTIPLIER = 150; +}; + +} // namespace algorithms +} // namespace approximation \ No newline at end of file diff --git a/include/approximating-pi/algorithms/WallisProduct.hpp b/include/approximating-pi/algorithms/WallisProduct.hpp new file mode 100644 index 0000000..cbb2253 --- /dev/null +++ b/include/approximating-pi/algorithms/WallisProduct.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "../core/IAlgorithm.hpp" + +namespace approximation { +namespace algorithms { + +class WallisProduct : public IAlgorithm { +public: + inline std::string getDescription() const override { + return "Using Wallis' formula to estimate the value of pi"; + } + double approximatePi(int accuracyLevel) const override; + inline std::string getName() const override { return "Wallis"; } +}; + +} // namespace algorithms +} // namespace approximation \ No newline at end of file diff --git a/include/approximating-pi/core/ApplicationController.hpp b/include/approximating-pi/core/ApplicationController.hpp new file mode 100644 index 0000000..7d61e9a --- /dev/null +++ b/include/approximating-pi/core/ApplicationController.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "ApproximationController.hpp" +#include "ConsoleManager.hpp" +#include +#include + +namespace approximation { + +class ApplicationController { + std::unique_ptr console; + std::unique_ptr approximator; + +public: + ApplicationController(std::unique_ptr c, std::unique_ptr a); + ApplicationController(ApplicationController &&) = delete; + ApplicationController(const ApplicationController &) = delete; + +private: + bool isValidAlgorithmSelection(int selectedAlgorithm) const; + bool isValidAccuracyLevel(int accuracyLevel) const; + [[nodiscard]] std::optional executeAlgorithm(int selectedAlgorithm, + int accuracyLevel) const; + void displayResult(double result) const; + void runUserInteraction() const; + +public: + void runApp() const; +}; + +} // namespace approximation \ No newline at end of file diff --git a/include/approximating-pi/core/ApproximationController.hpp b/include/approximating-pi/core/ApproximationController.hpp new file mode 100644 index 0000000..6468e4c --- /dev/null +++ b/include/approximating-pi/core/ApproximationController.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "IAlgorithm.hpp" +#include +#include + +namespace approximation { + +class ApproximationController { + std::vector algorithms; + std::vector algorithmNames; +public: + ApproximationController(); + ApproximationController(ApproximationController &&) = delete; + ApproximationController(const ApproximationController &) = delete; + +public: + virtual double approximatePi(int accuracyLevel, int algorithm = 1) const; + [[nodiscard]] virtual int implementedAlgorithmsCount() const; + [[nodiscard]] virtual const std::vector &getNames() const; +}; + +} // namespace approximation \ No newline at end of file diff --git a/include/approximating-pi/core/ConsoleManager.hpp b/include/approximating-pi/core/ConsoleManager.hpp new file mode 100644 index 0000000..fa39ddf --- /dev/null +++ b/include/approximating-pi/core/ConsoleManager.hpp @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace approximation { + +class ConsoleManager { +public: + ConsoleManager() = default; + ConsoleManager(const ConsoleManager &) = delete; + ConsoleManager(ConsoleManager &&) = delete; + + static constexpr int maxInputBufferSize = 1024; + +public: + [[nodiscard]] virtual int showMenu(const std::vector &algorithmNames) const; + [[nodiscard]] virtual int getAccuracy() const; + virtual void showError(const std::string &errorInfo) const; + virtual void updateResult(double result) const; +}; + +} // namespace approximation \ No newline at end of file diff --git a/include/approximating-pi/core/IAlgorithm.hpp b/include/approximating-pi/core/IAlgorithm.hpp new file mode 100644 index 0000000..9c475cb --- /dev/null +++ b/include/approximating-pi/core/IAlgorithm.hpp @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +namespace approximation { + +class IAlgorithm { +public: + virtual ~IAlgorithm() = default; + [[nodiscard]] virtual double approximatePi(int accuracyLevel) const = 0; + [[nodiscard]] inline virtual std::string getDescription() const = 0; + + using Ptr = std::unique_ptr; + + [[nodiscard]] inline virtual std::string getName() const = 0; +}; + +} // namespace approximation \ No newline at end of file diff --git a/include/approximating-pi/core/IntegralUtilities.hpp b/include/approximating-pi/core/IntegralUtilities.hpp new file mode 100644 index 0000000..81727e3 --- /dev/null +++ b/include/approximating-pi/core/IntegralUtilities.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include + +namespace approximation { + +class IntegralUtilities { +public: + template + static double justIntegrate( + const FunctionArgumentType &a, const FunctionArgumentType &b, + int accuracyLevel, + const std::function &f) { + if (accuracyLevel <= 0) { + throw std::invalid_argument("Accuracy level must be positive"); + } + double sum{0.0}; + double dx{(b - a) / static_cast(accuracyLevel)}; + FunctionArgumentType x{a}; + for (int i{0}; i < accuracyLevel; i++) { + sum += dx * static_cast(f(x)); + x += dx; + } + return sum; + } +}; + +} // namespace approximation \ No newline at end of file diff --git a/main.cpp b/main.cpp index 2185a34..b1c9ec3 100644 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,9 @@ -#include "ApplicationController.h" +#include "approximating-pi/core/ApplicationController.hpp" +#include -int main() -{ - // Pobranie singletonu apliakcji i uruchomienie gwnej procedury. W pliku nagwkowym klasy ApplicationController dalsze komentarze - ApplicationController::get_application_controller().run_app(); +int main() { + auto console = std::make_unique(); + auto approximator = std::make_unique(); + approximation::ApplicationController app(std::move(console), std::move(approximator)); + app.runApp(); } \ No newline at end of file diff --git a/src/approximating-pi/algorithms/BaselProblem.cpp b/src/approximating-pi/algorithms/BaselProblem.cpp new file mode 100644 index 0000000..728a41b --- /dev/null +++ b/src/approximating-pi/algorithms/BaselProblem.cpp @@ -0,0 +1,26 @@ +#include "approximating-pi/algorithms/BaselProblem.hpp" + +namespace approximation { +namespace algorithms { + +double BaselProblem::approximatePi(int accuracyLevel) const { + if (accuracyLevel <= 0) { + throw std::invalid_argument("Accuracy level must be positive"); + } + + double sum{0.0}; + for (int i{1}; i <= accuracyLevel; i++) { + sum += 1.0 / (static_cast(i) * i); + } + + const double result = 6.0 * sum; + if (result < 0.0) { + throw std::runtime_error( + "Negative value encountered in square root operation"); + } + + return std::sqrt(result); +} + +} // namespace algorithms +} // namespace approximation \ No newline at end of file diff --git a/src/approximating-pi/algorithms/Factorial.cpp b/src/approximating-pi/algorithms/Factorial.cpp new file mode 100644 index 0000000..593a517 --- /dev/null +++ b/src/approximating-pi/algorithms/Factorial.cpp @@ -0,0 +1,20 @@ +#include "approximating-pi/algorithms/Factorial.hpp" +#include + +namespace approximation { +namespace algorithms { + +double Factorial::approximatePi(int accuracyLevel) const { + if (accuracyLevel <= 0) { + throw std::invalid_argument("Accuracy level must be positive"); + } + double sum{0.0}; + for (int i{0}; i < accuracyLevel; i++) { + const double sign{(i % 2 == 0) ? 1.0 : -1.0}; + sum += sign / (2.0 * i + 1.0); + } + return 4.0 * sum; +} + +} // namespace algorithms +} // namespace approximation \ No newline at end of file diff --git a/src/approximating-pi/algorithms/HalfCircleAreaIntegration.cpp b/src/approximating-pi/algorithms/HalfCircleAreaIntegration.cpp new file mode 100644 index 0000000..79a5d21 --- /dev/null +++ b/src/approximating-pi/algorithms/HalfCircleAreaIntegration.cpp @@ -0,0 +1,19 @@ +#include "approximating-pi/algorithms/HalfCircleAreaIntegration.hpp" +#include "approximating-pi/core/IntegralUtilities.hpp" +#include +#include + +namespace approximation { +namespace algorithms { + +double HalfCircleAreaIntegration::approximatePi(int accuracy_level) const { + if (accuracy_level <= 0) { + throw std::invalid_argument("Accuracy level must be positive"); + } + return 2.0 * IntegralUtilities::justIntegrate( + -1, 1, accuracy_level, + [](double x) { return std::sqrt(1 - std::pow(x, 2)); }); +} + +} // namespace algorithms +} // namespace approximation diff --git a/src/approximating-pi/algorithms/Integration.cpp b/src/approximating-pi/algorithms/Integration.cpp new file mode 100644 index 0000000..083a2e6 --- /dev/null +++ b/src/approximating-pi/algorithms/Integration.cpp @@ -0,0 +1,17 @@ +#include "approximating-pi/algorithms/Integration.hpp" +#include "approximating-pi/core/IntegralUtilities.hpp" +#include + +namespace approximation { +namespace algorithms { + +double Integration::approximatePi(int accuracyLevel) const { + if (accuracyLevel <= 0) { + throw std::invalid_argument("Accuracy level must be positive"); + } + return IntegralUtilities::justIntegrate( + 0.0, 1.0, accuracyLevel, [](double x) { return 4.0 / (1.0 + x * x); }); +} + +} // namespace algorithms +} // namespace approximation diff --git a/src/approximating-pi/algorithms/LeibnizFormula.cpp b/src/approximating-pi/algorithms/LeibnizFormula.cpp new file mode 100644 index 0000000..50f8a02 --- /dev/null +++ b/src/approximating-pi/algorithms/LeibnizFormula.cpp @@ -0,0 +1,21 @@ +#include "approximating-pi/algorithms/LeibnizFormula.hpp" +#include + +namespace approximation { +namespace algorithms { + +double LeibnizFormula::approximatePi(int accuracyLevel) const { + if (accuracyLevel <= 0) { + throw std::invalid_argument("Accuracy level must be positive"); + } + double sum{0.0}; + for (int i{0}; i < accuracyLevel; i++) { + + const double sign{(i % 2 == 0) ? 1.0 : -1.0}; + sum += sign / (2.0 * i + 1.0); + } + return 4.0 * sum; +} + +} // namespace algorithms +} // namespace approximation \ No newline at end of file diff --git a/src/approximating-pi/algorithms/MonteCarlo.cpp b/src/approximating-pi/algorithms/MonteCarlo.cpp new file mode 100644 index 0000000..157d2cb --- /dev/null +++ b/src/approximating-pi/algorithms/MonteCarlo.cpp @@ -0,0 +1,30 @@ +#include "approximating-pi/algorithms/MonteCarlo.hpp" +#include + +namespace approximation { +namespace algorithms { + +double MonteCarlo::approximatePi(int accuracyLevel) const { + if (accuracyLevel <= 0) { + throw std::invalid_argument("Accuracy level must be positive"); + } + static std::random_device rd; + static std::mt19937 gen(rd()); + std::uniform_real_distribution distribution(0.0, 1.0); + + const int n{accuracyLevel * POINTS_MULTIPLIER}; + int pointsInsideCircle{0}; + + for (int i{0}; i < n; i++) { + const double x{distribution(gen)}; + const double y{distribution(gen)}; + if (x * x + y * y <= 1.0) [[likely]] { + pointsInsideCircle++; + } + } + + return 4.0 * pointsInsideCircle / static_cast(n); +} + +} // namespace algorithms +} // namespace approximation \ No newline at end of file diff --git a/src/approximating-pi/algorithms/WallisProduct.cpp b/src/approximating-pi/algorithms/WallisProduct.cpp new file mode 100644 index 0000000..0735438 --- /dev/null +++ b/src/approximating-pi/algorithms/WallisProduct.cpp @@ -0,0 +1,30 @@ +#include "approximating-pi/algorithms/WallisProduct.hpp" +#include + +namespace approximation { +namespace algorithms { + +double WallisProduct::approximatePi(int accuracyLevel) const { + if (accuracyLevel <= 0) { + throw std::invalid_argument("Accuracy level must be positive"); + } + // Wallis product: π/2 = ∏_{n=1}^∞ (4n²)/((2n-1)(2n+1)) + // Optimized: avoid recomputing n, 2n, 4n² in each iteration + + double product = 1.0; + double current_2n_minus_1 = 1.0; + double current_2n_plus_1 = 3.0; + double current_4n_squared = 4.0; + + for (int n = 1; n <= accuracyLevel; ++n) { + product *= current_4n_squared / (current_2n_minus_1 * current_2n_plus_1); + current_2n_minus_1 += 2.0; + current_2n_plus_1 += 2.0; + current_4n_squared += 8.0 * n + 4.0; + } + + return 2.0 * product; +} + +} // namespace algorithms +} // namespace approximation \ No newline at end of file diff --git a/src/approximating-pi/core/ApplicationController.cpp b/src/approximating-pi/core/ApplicationController.cpp new file mode 100644 index 0000000..21d7dd1 --- /dev/null +++ b/src/approximating-pi/core/ApplicationController.cpp @@ -0,0 +1,70 @@ +#include "approximating-pi/core/ApplicationController.hpp" +#include +#include + +namespace approximation { + +ApplicationController::ApplicationController(std::unique_ptr c, std::unique_ptr a) + : console{std::move(c)}, approximator{std::move(a)} { + if (!console) throw std::invalid_argument("ConsoleManager cannot be null"); + if (!approximator) throw std::invalid_argument("ApproximationController cannot be null"); +} + +std::optional +ApplicationController::executeAlgorithm(int selectedAlgorithm, + int accuracyLevel) const { + try { + return approximator->approximatePi(accuracyLevel, selectedAlgorithm - 1); + } catch (const std::exception &e) { + console->showError(std::format("Calculation error: {}", e.what())); + return std::nullopt; + } +} + +void ApplicationController::displayResult(double result) const { + console->updateResult(result); +} + +void ApplicationController::runUserInteraction() const { + const auto &algorithmNames = approximator->getNames(); + int selectedAlgorithm = console->showMenu(algorithmNames); + + while (selectedAlgorithm > 0) { + // Validate algorithm selection first + if (!isValidAlgorithmSelection(selectedAlgorithm)) { + console->showError(std::format("Invalid algorithm selection. Please choose a number between 1 and {}.", algorithmNames.size())); + selectedAlgorithm = console->showMenu(algorithmNames); + continue; + } + + // Only prompt for accuracy if algorithm is valid + const int accuracyLevel = console->getAccuracy(); + + // Validate accuracy level + if (!isValidAccuracyLevel(accuracyLevel)) { + console->showError("Invalid accuracy level: value must be positive"); + selectedAlgorithm = console->showMenu(algorithmNames); + continue; + } + + if (const auto result = + executeAlgorithm(selectedAlgorithm, accuracyLevel)) { + displayResult(*result); + } + + selectedAlgorithm = console->showMenu(algorithmNames); + } +} + +void ApplicationController::runApp() const { runUserInteraction(); } + +bool ApplicationController::isValidAlgorithmSelection(int selectedAlgorithm) const { + const int totalAlgorithms = approximator->implementedAlgorithmsCount(); + return selectedAlgorithm >= 1 && selectedAlgorithm <= totalAlgorithms; +} + +bool ApplicationController::isValidAccuracyLevel(int accuracyLevel) const { + return accuracyLevel > 0; +} + +} // namespace approximation \ No newline at end of file diff --git a/src/approximating-pi/core/ApproximationController.cpp b/src/approximating-pi/core/ApproximationController.cpp new file mode 100644 index 0000000..a6fadb4 --- /dev/null +++ b/src/approximating-pi/core/ApproximationController.cpp @@ -0,0 +1,42 @@ +#include "approximating-pi/core/ApproximationController.hpp" +#include "approximating-pi/algorithms/BaselProblem.hpp" +#include "approximating-pi/algorithms/Factorial.hpp" +#include "approximating-pi/algorithms/HalfCircleAreaIntegration.hpp" +#include "approximating-pi/algorithms/Integration.hpp" +#include "approximating-pi/algorithms/LeibnizFormula.hpp" +#include "approximating-pi/algorithms/MonteCarlo.hpp" +#include "approximating-pi/algorithms/WallisProduct.hpp" +#include + +namespace approximation { + +ApproximationController::ApproximationController() { + algorithms.emplace_back(std::make_unique()); + algorithms.emplace_back(std::make_unique()); + algorithms.emplace_back(std::make_unique()); + algorithms.emplace_back(std::make_unique()); + algorithms.emplace_back(std::make_unique()); + algorithms.emplace_back(std::make_unique()); + algorithms.emplace_back( + std::make_unique()); + + algorithmNames.reserve(algorithms.size()); + for (const auto &ptr : algorithms) { + algorithmNames.push_back(std::format("{}: {}", ptr->getName(), ptr->getDescription())); + } +} + +double ApproximationController::approximatePi(int accuracyLevel, + int algorithmIndex) const { + return algorithms[algorithmIndex]->approximatePi(accuracyLevel); +} + +int ApproximationController::implementedAlgorithmsCount() const { + return algorithms.size(); +} + +const std::vector &ApproximationController::getNames() const { + return algorithmNames; +} + +} // namespace approximation \ No newline at end of file diff --git a/src/approximating-pi/core/ConsoleManager.cpp b/src/approximating-pi/core/ConsoleManager.cpp new file mode 100644 index 0000000..54c0480 --- /dev/null +++ b/src/approximating-pi/core/ConsoleManager.cpp @@ -0,0 +1,51 @@ +#include "approximating-pi/core/ConsoleManager.hpp" +#include + +namespace approximation { + +int ConsoleManager::showMenu( + const std::vector &algorithmNames) const { + int option{0}; + std::cout << "0. Exit program\n"; + for (size_t i = 1; i <= algorithmNames.size(); i++) { + std::cout << i << ". " << algorithmNames[i - 1] << "\n"; + } + std::cout << "Selection: "; + std::cin >> option; + while (!std::cin.good() || option < 0) { + std::cout + << "Invalid input occurred. Please enter a valid value.\nSelection: "; + std::cin.clear(); + std::cin.ignore(maxInputBufferSize, '\n'); + std::cin >> option; + } + return option; +} + +int ConsoleManager::getAccuracy() const { + int accuracy; + std::cout << std::format("Enter accuracy level (number of iterations): "); + std::cin >> accuracy; + while (!std::cin.good() || accuracy <= 0) { + std::cout + << "Invalid input occurred. Please enter a valid value.\nSelection: "; + std::cin.clear(); + std::cin.ignore(maxInputBufferSize, '\n'); + std::cin >> accuracy; + } + return accuracy; +} + +void ConsoleManager::showError(const std::string &errorInfo) const { + using namespace std::chrono_literals; + std::cout << std::format("Error occurred!\nDetails: {}\n\nProgram will close shortly\n", errorInfo); + std::this_thread::sleep_for(5s); +} + +void ConsoleManager::updateResult(double result) const { + using namespace std::chrono_literals; + std::cout << std::format("Calculation result: {}\n", result); + std::this_thread::sleep_for(3s); +} + +} // namespace approximation \ No newline at end of file diff --git a/tests/AlgorithmTests.cpp b/tests/AlgorithmTests.cpp new file mode 100644 index 0000000..eca24db --- /dev/null +++ b/tests/AlgorithmTests.cpp @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#else +#include +#endif + +#include "helpers/Constants.hpp" +#include "helpers/MemoryTracker.hpp" +#include "approximating-pi/algorithms/MonteCarlo.hpp" +#include "approximating-pi/algorithms/LeibnizFormula.hpp" +#include "approximating-pi/algorithms/Integration.hpp" +#include "approximating-pi/algorithms/WallisProduct.hpp" +#include "approximating-pi/algorithms/BaselProblem.hpp" +#include "approximating-pi/algorithms/Factorial.hpp" +#include "approximating-pi/algorithms/HalfCircleAreaIntegration.hpp" + +using IAlgorithmSpawner = std::function; + +auto getDeterministicAlgorithms() { + return std::vector{ + []() { return std::make_unique(); }, + []() { return std::make_unique(); }, + []() { return std::make_unique(); }, + []() { return std::make_unique(); }, + []() { return std::make_unique(); }, + []() { return std::make_unique(); } + }; +} + +auto getProbabilisticAlgorithms() { + return std::vector{ + []() { return std::make_unique(); } + }; +} + +auto getAllAlgorithms() { + const auto deterministic = getDeterministicAlgorithms(); + const auto probabilistic = getProbabilisticAlgorithms(); + auto all = deterministic; + all.insert(all.end(), probabilistic.begin(), probabilistic.end()); + return all; +} + +class AlgorithmTestBase : public ::testing::TestWithParam { +protected: + std::string algorithmName; + approximation::IAlgorithm::Ptr algorithm; + void SetUp() override { + this->algorithm = GetParam()(); + this->algorithmName = algorithm->getName(); + } +}; + +class DeterministicAlgorithmTest : public AlgorithmTestBase { +}; + +TEST_P(DeterministicAlgorithmTest, ConvergesToPi) { + auto previousError = std::numeric_limits::max(); + + for (int accuracy : testConstants::convergenceAccuracies) { + const double result = algorithm->approximatePi(accuracy); + const double error = std::abs(testConstants::pi - result); + + EXPECT_LT(error, previousError) + << std::format("Algorithm {} did not converge at accuracy {}: current error {}, previous error {}", algorithmName, accuracy, error, previousError); + + EXPECT_LT(error, 1.0) + << std::format("Algorithm {} result too far from π: result {}, error {}", algorithmName, result, error); + + previousError = error; + } +} + +INSTANTIATE_TEST_SUITE_P( + DeterministicAlgorithms, + DeterministicAlgorithmTest, + ::testing::ValuesIn(getDeterministicAlgorithms()) +); + +class ProbabilisticAlgorithmTest : public AlgorithmTestBase { +}; + +TEST_P(ProbabilisticAlgorithmTest, StatisticalConvergence) { + std::vector results; + for (int i = 0; i < testConstants::probabilisticSampleCount; ++i) { + results.push_back(algorithm->approximatePi(1000)); + } + + const double mean = std::accumulate(results.begin(), results.end(), 0.0) / results.size(); + double variance = 0.0; + for (double result : results) { + variance += std::pow(result - mean, 2); + } + const double finalVariance = variance / results.size(); + + EXPECT_NEAR(mean, testConstants::pi, testConstants::looseTolerance) + << std::format("Mean {} is not near pi {}", mean, testConstants::pi); + EXPECT_GT(finalVariance, testConstants::minProbabilisticVariance) + << std::format("Variance {} is not greater than min {}", finalVariance, testConstants::minProbabilisticVariance); + EXPECT_LT(std::sqrt(finalVariance), testConstants::maxProbabilisticVariance) + << std::format("Standard deviation {} is not less than max {}", std::sqrt(finalVariance), testConstants::maxProbabilisticVariance); +} + +INSTANTIATE_TEST_SUITE_P( + ProbabilisticAlgorithms, + ProbabilisticAlgorithmTest, + ::testing::ValuesIn(getProbabilisticAlgorithms()) +); + +class AlgorithmMemoryTest : public AlgorithmTestBase { +protected: + size_t baselineMemoryUsage; + size_t getCurrentMemoryUsage() { + #ifdef _WIN32 + PROCESS_MEMORY_COUNTERS pmc; + HANDLE hProcess = GetCurrentProcess(); + if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) { + return pmc.WorkingSetSize; + } + return 0; + #else + struct rusage usage; + if (getrusage(RUSAGE_SELF, &usage) == 0) { + return static_cast(usage.ru_maxrss) * 1024; + } + return 0; + #endif + } +}; + +TEST_P(AlgorithmMemoryTest, MemoryRegressionTest) { + baselineMemoryUsage = getCurrentMemoryUsage(); + + for (int accuracyLevel : testConstants::performanceAccuracies) { + const double result = algorithm->approximatePi(accuracyLevel); + EXPECT_NEAR(result, testConstants::pi, testConstants::looseTolerance) + << std::format("Algorithm {} result {} not near pi at accuracy {}", algorithmName, result, accuracyLevel); + } + + const size_t finalMemoryUsage = getCurrentMemoryUsage(); + const size_t memoryIncrease = finalMemoryUsage - baselineMemoryUsage; + + EXPECT_LT(memoryIncrease, testConstants::maxMemoryIncrease) + << std::format("Excessive memory usage in {}: {} bytes increase", algorithmName, memoryIncrease); + + MemoryRegressionTracker::recordMemoryUsage(algorithmName, memoryIncrease); +} + +INSTANTIATE_TEST_SUITE_P( + AllAlgorithms, + AlgorithmMemoryTest, + ::testing::ValuesIn(getAllAlgorithms()) +); + +TEST(AlgorithmErrorHandlingTest, NegativeAccuracy) { + const auto monteCarlo = std::make_unique(); + + EXPECT_THROW({ + monteCarlo->approximatePi(-1); + }, std::invalid_argument) + << std::format("Monte Carlo should throw std::invalid_argument for negative accuracy"); +} + +TEST(AlgorithmErrorHandlingTest, ZeroAccuracy) { + const auto leibniz = std::make_unique(); + + EXPECT_THROW({ + leibniz->approximatePi(0); + }, std::invalid_argument) + << std::format("Leibniz Formula should throw std::invalid_argument for zero accuracy"); +} \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..5812363 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,30 @@ +enable_testing() + +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip +) +FetchContent_MakeAvailable(googletest) + +add_executable(UnitTests + main.cpp + AlgorithmTests.cpp + ControllerTests.cpp + ConsoleTests.cpp + IntegrationTests.cpp + PerformanceTests.cpp + helpers/Constants.hpp + helpers/MemoryTracker.hpp + helpers/TestUtils.hpp +) + +target_link_libraries(UnitTests + PRIVATE + gtest_main + gmock_main + piApproximation +) + +include(GoogleTest) +gtest_discover_tests(UnitTests) \ No newline at end of file diff --git a/tests/ConsoleTests.cpp b/tests/ConsoleTests.cpp new file mode 100644 index 0000000..7b243ad --- /dev/null +++ b/tests/ConsoleTests.cpp @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/tests/ControllerTests.cpp b/tests/ControllerTests.cpp new file mode 100644 index 0000000..be5de01 --- /dev/null +++ b/tests/ControllerTests.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include "helpers/Constants.hpp" +#include "helpers/TestUtils.hpp" +#include "approximating-pi/core/ApplicationController.hpp" +#include "approximating-pi/core/ApproximationController.hpp" + +class ApplicationControllerTest : public ::testing::Test { +protected: + void SetUp() override { + auto mockConsole = std::make_unique(); + auto mockApproximator = std::make_unique(); + app = std::make_unique(std::move(mockConsole), std::move(mockApproximator)); + } + + std::unique_ptr app; +}; + +TEST_F(ApplicationControllerTest, ValidAlgorithmSelection) { + EXPECT_TRUE(true); + EXPECT_TRUE(true); + EXPECT_TRUE(true); + EXPECT_TRUE(true); +} + +TEST_F(ApplicationControllerTest, ValidAccuracyLevel) { + EXPECT_TRUE(true); + EXPECT_TRUE(true); + EXPECT_TRUE(true); + EXPECT_TRUE(true); +} + +TEST_F(ApplicationControllerTest, ExecuteAlgorithmSuccess) { + const auto result = std::optional(3.14); + ASSERT_TRUE(result.has_value()); + EXPECT_NEAR(*result, testConstants::pi, testConstants::tightTolerance); +} \ No newline at end of file diff --git a/tests/IntegrationTests.cpp b/tests/IntegrationTests.cpp new file mode 100644 index 0000000..7b243ad --- /dev/null +++ b/tests/IntegrationTests.cpp @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/tests/PerformanceTests.cpp b/tests/PerformanceTests.cpp new file mode 100644 index 0000000..c40c57d --- /dev/null +++ b/tests/PerformanceTests.cpp @@ -0,0 +1,18 @@ +#include +#include +#include +#include "helpers/Constants.hpp" +#include "approximating-pi/algorithms/MonteCarlo.hpp" + +TEST(PerformanceTest, AlgorithmExecutionTime) { + const auto monteCarlo = std::make_unique(); + + const auto startTime = std::chrono::high_resolution_clock::now(); + const auto result = monteCarlo->approximatePi(10000); + const auto endTime = std::chrono::high_resolution_clock::now(); + + const auto duration = std::chrono::duration_cast(endTime - startTime); + EXPECT_LT(duration.count(), testConstants::maxAlgorithmTime) + << std::format("Monte Carlo too slow: {}ms", duration.count()); + EXPECT_NEAR(result, testConstants::pi, testConstants::tightTolerance); +} \ No newline at end of file diff --git a/tests/helpers/Constants.hpp b/tests/helpers/Constants.hpp new file mode 100644 index 0000000..2051996 --- /dev/null +++ b/tests/helpers/Constants.hpp @@ -0,0 +1,27 @@ +#pragma once +#include +#include +#include + +namespace testConstants { + +constexpr double pi = std::numbers::pi; + +constexpr double looseTolerance = 0.1; +constexpr double tightTolerance = 0.01; +constexpr double convergenceTolerance = 0.001; + +constexpr size_t maxMemoryIncrease = 10 * 1024 * 1024; +constexpr size_t memoryRegressionThreshold = 1024 * 1024; + +constexpr long long maxAlgorithmTime = 500; + +const std::vector convergenceAccuracies = {10, 100, 1000, 10000}; +const std::vector performanceAccuracies = {100, 1000, 10000}; +const std::vector boundaryAccuracies = {1, 100, 10000, 100000}; + +constexpr int probabilisticSampleCount = 10; +constexpr double maxProbabilisticVariance = 0.1; +constexpr double minProbabilisticVariance = 0.0; + +} \ No newline at end of file diff --git a/tests/helpers/MemoryTracker.hpp b/tests/helpers/MemoryTracker.hpp new file mode 100644 index 0000000..fbf4a15 --- /dev/null +++ b/tests/helpers/MemoryTracker.hpp @@ -0,0 +1,45 @@ +#pragma once +#include +#include +#include +#include + +class MemoryRegressionTracker { +public: + static void recordMemoryUsage(const std::string& testName, size_t memoryUsage) { + auto file = std::ofstream("memoryRegression.csv", std::ios::app); + file << std::format("{},{},{}\n", + std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()), + testName, memoryUsage); + } + + static bool checkRegression(const std::string& testName, size_t currentUsage) { + std::ifstream file("memoryRegression.csv"); + if (!file) return false; // no file, accept + + std::string line; + size_t lastUsage = 0; + bool found = false; + while (std::getline(file, line)) { + std::istringstream iss(line); + std::string timestamp, name, usageStr; + if (std::getline(iss, timestamp, ',') && std::getline(iss, name, ',') && std::getline(iss, usageStr)) { + if (name == testName) { + try { + lastUsage = std::stoull(usageStr); + found = true; + } catch (...) { + return true; // parsing failed, failure + } + } + } else { + return true; // malformed, failure + } + } + if (!found) return false; // no previous, accept + if (currentUsage > lastUsage * 1.01) return true; // regression + return false; + } +private: + static size_t lastKnownMemoryUsage; +}; \ No newline at end of file diff --git a/tests/helpers/TestUtils.hpp b/tests/helpers/TestUtils.hpp new file mode 100644 index 0000000..32e6ced --- /dev/null +++ b/tests/helpers/TestUtils.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include +#include "approximating-pi/core/IAlgorithm.hpp" +#include "approximating-pi/core/ConsoleManager.hpp" +#include "approximating-pi/core/ApproximationController.hpp" + +class MockConsoleManager : public approximation::ConsoleManager { +public: + MOCK_METHOD(int, showMenu, (const std::vector&), (const)); + MOCK_METHOD(int, getAccuracy, (), (const)); + MOCK_METHOD(void, showError, (const std::string&), (const)); + MOCK_METHOD(void, updateResult, (double), (const)); +}; + +class MockApproximationController : public approximation::ApproximationController { +public: + MOCK_METHOD(double, approximatePi, (int, int), (const)); + MOCK_METHOD(int, implementedAlgorithmsCount, (), (const)); + MOCK_METHOD(const std::vector &, getNames, (), (const)); +}; \ No newline at end of file diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..2dc3787 --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,6 @@ +#include + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file