From 5e8596dd8d0b3b8ed8736f8c73e8f9936dbe26df Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Sat, 1 May 2021 22:31:59 +0900 Subject: [PATCH] Working C++ impl --- cpp_impl/Makefile | 2 +- cpp_impl/src/geometric_mean.cpp | 21 +++++++ cpp_impl/src/geometric_mean.hpp | 6 ++ cpp_impl/src/geothmetic_meandian.cpp | 83 ++++++++++++++++++++++++++++ cpp_impl/src/geothmetic_meandian.hpp | 8 +++ cpp_impl/src/helpers.cpp | 16 ++++++ cpp_impl/src/helpers.hpp | 6 ++ cpp_impl/src/main.cpp | 36 ++++++++++++ 8 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 cpp_impl/src/geometric_mean.cpp create mode 100644 cpp_impl/src/geometric_mean.hpp create mode 100644 cpp_impl/src/geothmetic_meandian.cpp create mode 100644 cpp_impl/src/geothmetic_meandian.hpp create mode 100644 cpp_impl/src/helpers.cpp create mode 100644 cpp_impl/src/helpers.hpp diff --git a/cpp_impl/Makefile b/cpp_impl/Makefile index 6356389..fcc5998 100644 --- a/cpp_impl/Makefile +++ b/cpp_impl/Makefile @@ -8,7 +8,7 @@ endif all: GeothmeticMeandian -GeothmeticMeandian: src/main.o +GeothmeticMeandian: src/main.o src/geometric_mean.o src/geothmetic_meandian.o src/helpers.o $(CXX) $(CXXFLAGS) -o GeothmeticMeandian $^ .PHONY: diff --git a/cpp_impl/src/geometric_mean.cpp b/cpp_impl/src/geometric_mean.cpp new file mode 100644 index 0000000..d81afff --- /dev/null +++ b/cpp_impl/src/geometric_mean.cpp @@ -0,0 +1,21 @@ +#include "geometric_mean.hpp" + +#include +#include + +#include "helpers.hpp" + +double geometric_mean(double a, double b) { + double temp_a; + double temp_b; + + while(!floating_point_similar(a, b, 5)) { + temp_a = a; + temp_b = b; + + a = (temp_a + temp_b) / 2.0; + b = std::sqrt(temp_a * temp_b); + } + + return a; +} diff --git a/cpp_impl/src/geometric_mean.hpp b/cpp_impl/src/geometric_mean.hpp new file mode 100644 index 0000000..72d7f33 --- /dev/null +++ b/cpp_impl/src/geometric_mean.hpp @@ -0,0 +1,6 @@ +#ifndef GEOMETRIC_MEAN_HPP +#define GEOMETRIC_MEAN_HPP + +double geometric_mean(double a, double b); + +#endif diff --git a/cpp_impl/src/geothmetic_meandian.cpp b/cpp_impl/src/geothmetic_meandian.cpp new file mode 100644 index 0000000..d7bcad8 --- /dev/null +++ b/cpp_impl/src/geothmetic_meandian.cpp @@ -0,0 +1,83 @@ +#include "geothmetic_meandian.hpp" + +#include +#include +#include +#include + +#include "helpers.hpp" + +bool is_all_equal(const std::array &values) { +// return std::all_of(values.begin(), values.end(), floating_point_similar); + + /* + double first = values.at(0); + for(std::size_t i = 1; i < values.size(); ++i) { + if(values[i] != first) { + return false; + } + } + return true; + */ + return floating_point_similar(values[0], values[1], 5) + && floating_point_similar(values[1], values[2], 5); +} + +double geothmetic_meandian(std::vector values) { + if(values.empty()) { + return 0.0; + } else if(values.size() == 1) { + return values[0]; + } + + std::sort(values.begin(), values.end()); + + std::array current, temp; + bool isFirstIteration = true; + + do { + if(isFirstIteration) { + // mean + current[0] = std::accumulate( + values.begin(), + values.end(), + 0.0) + / values.size(); + // geometric mean + current[1] = std::accumulate( + values.begin(), + values.end(), + 1.0, + [] (const auto &a, const auto &b) { + return a * b; + }); + current[1] = std::pow(current[1], 1.0 / (double)values.size()); + // median + current[2] = values[values.size() / 2]; + isFirstIteration = false; + } else { + temp = current; + + // mean + current[0] = std::accumulate( + temp.begin(), + temp.end(), + 0.0) + / temp.size(); + // geometric mean + current[1] = std::accumulate( + temp.begin(), + temp.end(), + 1.0, + [] (const auto &a, const auto &b) { + return a * b; + }); + current[1] = std::pow(current[1], 1.0 / (double)temp.size()); + // median + std::sort(temp.begin(), temp.end()); + current[2] = temp[temp.size() / 2]; + } + } while(!is_all_equal(current)); + + return current[0]; +} diff --git a/cpp_impl/src/geothmetic_meandian.hpp b/cpp_impl/src/geothmetic_meandian.hpp new file mode 100644 index 0000000..c9479ab --- /dev/null +++ b/cpp_impl/src/geothmetic_meandian.hpp @@ -0,0 +1,8 @@ +#ifndef GEOTHMETIC_MEANDIAN_HPP +#define GEOTHMETIC_MEANDIAN_HPP + +#include + +double geothmetic_meandian(std::vector values); + +#endif diff --git a/cpp_impl/src/helpers.cpp b/cpp_impl/src/helpers.cpp new file mode 100644 index 0000000..f35011d --- /dev/null +++ b/cpp_impl/src/helpers.cpp @@ -0,0 +1,16 @@ +#include "helpers.hpp" + +#include + +bool floating_point_similar(double a, double b, unsigned char decimal) { + std::string astr = std::to_string(a); + std::string bstr = std::to_string(b); + + auto a_index = astr.find_last_of('.'); + astr = astr.substr(0, a_index + decimal); + + auto b_index = bstr.find_last_of('.'); + bstr = bstr.substr(0, b_index + decimal); + + return astr == bstr; +} diff --git a/cpp_impl/src/helpers.hpp b/cpp_impl/src/helpers.hpp new file mode 100644 index 0000000..0184a44 --- /dev/null +++ b/cpp_impl/src/helpers.hpp @@ -0,0 +1,6 @@ +#ifndef HELPERS_HPP +#define HELPERS_HPP + +bool floating_point_similar(double a, double b, unsigned char decimal = 5); + +#endif diff --git a/cpp_impl/src/main.cpp b/cpp_impl/src/main.cpp index 11b7fad..d9d804e 100644 --- a/cpp_impl/src/main.cpp +++ b/cpp_impl/src/main.cpp @@ -1,3 +1,39 @@ +#include +#include + +#include "geometric_mean.hpp" +#include "geothmetic_meandian.hpp" + int main(int argc, char **argv) { + --argc; ++argv; + + std::vector input; + double temp; + + while(argc > 0) { + temp = std::strtod(argv[0], nullptr); + if(temp == 0.0) { + puts("ERROR: Failed to parse double"); + return 1; + } else { + input.push_back(temp); + } + --argc; ++argv; + } + + printf("Got input:\n "); + for(double d : input) { + printf("%f ", d); + } + puts(""); + + if(input.size() == 2) { + printf("Geometric Mean of two doubles is %f\n", + geometric_mean(input[0], input[1])); + } else if(input.size() > 2) { + printf("Geomethic Meandian of input is %f\n", + geothmetic_meandian(input)); + } + return 0; }