From e8a0bf2c2ce4ebb155efbc3f792eaeb6ce05bbde Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 23 May 2020 19:26:11 -0400 Subject: [PATCH 1/9] compute stats of data in realtime (unknown length of data) - mean, variance and standard deviation --- math/realtime_stats.cpp | 106 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 math/realtime_stats.cpp diff --git a/math/realtime_stats.cpp b/math/realtime_stats.cpp new file mode 100644 index 000000000..af0c54ca9 --- /dev/null +++ b/math/realtime_stats.cpp @@ -0,0 +1,106 @@ +#include +#include + +/** + * continuous mean and variance computance using + * first value as an approximation for the mean + **/ +template class stats_computer1 +{ +public: + void new_val(T x) + { + if (n == 0) + K = x; + n++; + T tmp = x - K; + Ex += tmp; + Ex2 += tmp * tmp; + } + + double mean() const { return K + Ex / n; } + + double variance() const { return (Ex2 - (Ex * Ex) / n) / (n - 1); } + + double std() const { return std::sqrt(this->variance()); } + + friend std::istream &operator>>(std::istream &input, stats_computer1 &stat) + { + T val; + input >> val; + stat.new_val(val); + return input; + } + +private: + unsigned int n = 0; + double Ex, Ex2; + T K; +}; + +/** + * continuous mean and variance computance using + * Welford's algorithm + **/ +template class stats_computer2 +{ +public: + void new_val(T x) + { + n++; + double delta = x - mu; + mu += delta / n; + double delta2 = x - mu; + M += delta * delta2; + } + + double mean() const { return mu; } + + double variance() const { return M / n; } + + double std() const { return std::sqrt(this->variance()); } + + friend std::istream &operator>>(std::istream &input, stats_computer2 &stat) + { + T val; + input >> val; + stat.new_val(val); + return input; + } + +private: + unsigned int n = 0; + double mu = 0, var = 0, M = 0; +}; + +int main(int argc, char **argv) +{ + std::cout + << "Enter data. Any non-numeric data will terminate the data input." + << std::endl; + + stats_computer1 stats1; + stats_computer2 stats2; + + while (1) + { + double val; + std::cout << "Enter number: "; + std::cin >> val; + if (std::cin.fail()) // check for failure to read input. Happens for + // non-numeric data + break; + stats1.new_val(val); + stats2.new_val(val); + std::cout << "\tMethod 1:" + << "\tMean: " << stats1.mean() + << "\t Variance: " << stats1.variance() + << "\t Std: " << stats1.std() << std::endl; + std::cout << "\tMethod 2:" + << "\tMean: " << stats2.mean() + << "\t Variance: " << stats2.variance() + << "\t Std: " << stats2.std() << std::endl; + } + + return 0; +} \ No newline at end of file From e5d3316ef2e3572efcd7d72a8a2af0fd5ac661c3 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 23 May 2020 19:51:18 -0400 Subject: [PATCH 2/9] fixed formatting --- math/realtime_stats.cpp | 148 +++++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 78 deletions(-) diff --git a/math/realtime_stats.cpp b/math/realtime_stats.cpp index af0c54ca9..e1b8cfaa1 100644 --- a/math/realtime_stats.cpp +++ b/math/realtime_stats.cpp @@ -5,102 +5,94 @@ * continuous mean and variance computance using * first value as an approximation for the mean **/ -template class stats_computer1 -{ -public: - void new_val(T x) - { - if (n == 0) - K = x; - n++; - T tmp = x - K; - Ex += tmp; - Ex2 += tmp * tmp; - } +template +class stats_computer1 { + public: + void new_val(T x) { + if (n == 0) K = x; + n++; + T tmp = x - K; + Ex += tmp; + Ex2 += tmp * tmp; + } - double mean() const { return K + Ex / n; } + double mean() const { return K + Ex / n; } - double variance() const { return (Ex2 - (Ex * Ex) / n) / (n - 1); } + double variance() const { return (Ex2 - (Ex * Ex) / n) / (n - 1); } - double std() const { return std::sqrt(this->variance()); } + double std() const { return std::sqrt(this->variance()); } - friend std::istream &operator>>(std::istream &input, stats_computer1 &stat) - { - T val; - input >> val; - stat.new_val(val); - return input; - } + friend std::istream &operator>>(std::istream &input, stats_computer1 &stat) { + T val; + input >> val; + stat.new_val(val); + return input; + } -private: - unsigned int n = 0; - double Ex, Ex2; - T K; + private: + unsigned int n = 0; + double Ex, Ex2; + T K; }; /** * continuous mean and variance computance using * Welford's algorithm **/ -template class stats_computer2 -{ -public: - void new_val(T x) - { - n++; - double delta = x - mu; - mu += delta / n; - double delta2 = x - mu; - M += delta * delta2; - } +template +class stats_computer2 { + public: + void new_val(T x) { + n++; + double delta = x - mu; + mu += delta / n; + double delta2 = x - mu; + M += delta * delta2; + } - double mean() const { return mu; } + double mean() const { return mu; } - double variance() const { return M / n; } + double variance() const { return M / n; } - double std() const { return std::sqrt(this->variance()); } + double std() const { return std::sqrt(this->variance()); } - friend std::istream &operator>>(std::istream &input, stats_computer2 &stat) - { - T val; - input >> val; - stat.new_val(val); - return input; - } + friend std::istream &operator>>(std::istream &input, stats_computer2 &stat) { + T val; + input >> val; + stat.new_val(val); + return input; + } -private: - unsigned int n = 0; - double mu = 0, var = 0, M = 0; + private: + unsigned int n = 0; + double mu = 0, var = 0, M = 0; }; -int main(int argc, char **argv) -{ - std::cout - << "Enter data. Any non-numeric data will terminate the data input." - << std::endl; +int main(int argc, char **argv) { + std::cout << "Enter data. Any non-numeric data will terminate the data input." + << std::endl; - stats_computer1 stats1; - stats_computer2 stats2; + stats_computer1 stats1; + stats_computer2 stats2; - while (1) - { - double val; - std::cout << "Enter number: "; - std::cin >> val; - if (std::cin.fail()) // check for failure to read input. Happens for - // non-numeric data - break; - stats1.new_val(val); - stats2.new_val(val); - std::cout << "\tMethod 1:" - << "\tMean: " << stats1.mean() - << "\t Variance: " << stats1.variance() - << "\t Std: " << stats1.std() << std::endl; - std::cout << "\tMethod 2:" - << "\tMean: " << stats2.mean() - << "\t Variance: " << stats2.variance() - << "\t Std: " << stats2.std() << std::endl; - } + while (1) { + double val; + std::cout << "Enter number: "; + std::cin >> val; + if (std::cin.fail()) // check for failure to read input. Happens for + // non-numeric data + break; + stats1.new_val(val); + stats2.new_val(val); + std::cout << "\tMethod 1:" + << "\tMean: " << stats1.mean() + << "\t Variance: " << stats1.variance() + << "\t Std: " << stats1.std() << std::endl; + std::cout << "\tMethod 2:" + << "\tMean: " << stats2.mean() + << "\t Variance: " << stats2.variance() + << "\t Std: " << stats2.std() << std::endl; + } - return 0; -} \ No newline at end of file + return 0; +} From 9b61d570f139a93d4090aefbb60851180ea2b7a7 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sun, 24 May 2020 13:22:55 -0400 Subject: [PATCH 3/9] rebase conflict resolved --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0ab2708d0..e2efa1634 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -68,4 +68,4 @@ "editor.formatOnSave": true, "editor.formatOnType": true, "editor.formatOnPaste": true -} +} \ No newline at end of file From 6156f95571809dff9fd22ff70107a9457193ffd1 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 24 May 2020 17:23:51 +0000 Subject: [PATCH 4/9] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index ddbfd06d8..780eea03e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -116,6 +116,7 @@ * [Prime Factorization](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/prime_factorization.cpp) * [Prime Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/prime_numbers.cpp) * [Primes Up To 10^8](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/primes_up_to_10^8.cpp) + * [Realtime Stats](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/realtime_stats.cpp) * [Sieve Of Eratosthenes](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/sieve_of_eratosthenes.cpp) * [Sqrt Double](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/sqrt_double.cpp) From 6da2b9645a935542a971ba7a499ae0144347d92d Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sun, 24 May 2020 13:56:34 -0400 Subject: [PATCH 5/9] added missing newline character --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e2efa1634..0ab2708d0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -68,4 +68,4 @@ "editor.formatOnSave": true, "editor.formatOnType": true, "editor.formatOnPaste": true -} \ No newline at end of file +} From b596b7e42d2a370d7acc6b33a768cc9097c141b2 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 30 May 2020 09:35:27 -0400 Subject: [PATCH 6/9] added comments to the code --- math/realtime_stats.cpp | 149 ++++++++++++++++++++++++---------------- 1 file changed, 89 insertions(+), 60 deletions(-) diff --git a/math/realtime_stats.cpp b/math/realtime_stats.cpp index e1b8cfaa1..f853b8274 100644 --- a/math/realtime_stats.cpp +++ b/math/realtime_stats.cpp @@ -1,3 +1,11 @@ +/** + * \file + * \brief Compute statistics for data entered in rreal-time + * + * This algorithm is really beneficial to compute statistics on data read in + * realtime. For example, devices reading biometrics data. The algorithm is + * simple enough to be easily implemented in an embedded system. + */ #include #include @@ -8,31 +16,39 @@ template class stats_computer1 { public: - void new_val(T x) { - if (n == 0) K = x; - n++; - T tmp = x - K; - Ex += tmp; - Ex2 += tmp * tmp; - } + /** Constructor + * \param[in] x new data sample + */ + void new_val(T x) { + if (n == 0) K = x; + n++; + T tmp = x - K; + Ex += tmp; + Ex2 += tmp * tmp; + } - double mean() const { return K + Ex / n; } + /** return sample mean computed till last sample */ + double mean() const { return K + Ex / n; } - double variance() const { return (Ex2 - (Ex * Ex) / n) / (n - 1); } + /** return data variance computed till last sample */ + double variance() const { return (Ex2 - (Ex * Ex) / n) / (n - 1); } - double std() const { return std::sqrt(this->variance()); } + /** return sample standard deviation computed till last sample */ + double std() const { return std::sqrt(this->variance()); } - friend std::istream &operator>>(std::istream &input, stats_computer1 &stat) { - T val; - input >> val; - stat.new_val(val); - return input; - } + /** short-hand operator to read new sample from input stream */ + friend std::istream &operator>>(std::istream &input, + stats_computer1 &stat) { + T val; + input >> val; + stat.new_val(val); + return input; + } private: - unsigned int n = 0; - double Ex, Ex2; - T K; + unsigned int n = 0; + double Ex, Ex2; + T K; }; /** @@ -42,57 +58,70 @@ class stats_computer1 { template class stats_computer2 { public: - void new_val(T x) { - n++; - double delta = x - mu; - mu += delta / n; - double delta2 = x - mu; - M += delta * delta2; - } + /** Constructor + * \param[in] x new data sample + */ + void new_val(T x) { + n++; + double delta = x - mu; + mu += delta / n; + double delta2 = x - mu; + M += delta * delta2; + } - double mean() const { return mu; } + /** return sample mean computed till last sample */ + double mean() const { return mu; } - double variance() const { return M / n; } + /** return data variance computed till last sample */ + double variance() const { return M / n; } - double std() const { return std::sqrt(this->variance()); } + /** return sample standard deviation computed till last sample */ + double std() const { return std::sqrt(this->variance()); } - friend std::istream &operator>>(std::istream &input, stats_computer2 &stat) { - T val; - input >> val; - stat.new_val(val); - return input; - } + /** short-hand operator to read new sample from input stream */ + friend std::istream &operator>>(std::istream &input, + stats_computer2 &stat) { + T val; + input >> val; + stat.new_val(val); + return input; + } private: - unsigned int n = 0; - double mu = 0, var = 0, M = 0; + unsigned int n = 0; + double mu = 0, var = 0, M = 0; }; +/** Main function */ int main(int argc, char **argv) { - std::cout << "Enter data. Any non-numeric data will terminate the data input." - << std::endl; + std::cout + << "Enter data. Any non-numeric data will terminate the data input." + << std::endl; - stats_computer1 stats1; - stats_computer2 stats2; + stats_computer1 stats1; + stats_computer2 stats2; - while (1) { - double val; - std::cout << "Enter number: "; - std::cin >> val; - if (std::cin.fail()) // check for failure to read input. Happens for - // non-numeric data - break; - stats1.new_val(val); - stats2.new_val(val); - std::cout << "\tMethod 1:" - << "\tMean: " << stats1.mean() - << "\t Variance: " << stats1.variance() - << "\t Std: " << stats1.std() << std::endl; - std::cout << "\tMethod 2:" - << "\tMean: " << stats2.mean() - << "\t Variance: " << stats2.variance() - << "\t Std: " << stats2.std() << std::endl; - } + while (1) { + double val; + std::cout << "Enter number: "; + std::cin >> val; - return 0; + // check for failure to read input. Happens for + // non-numeric data + if (std::cin.fail()) break; + + stats1.new_val(val); + stats2.new_val(val); + + std::cout << "\tMethod 1:" + << "\tMean: " << stats1.mean() + << "\t Variance: " << stats1.variance() + << "\t Std: " << stats1.std() << std::endl; + std::cout << "\tMethod 2:" + << "\tMean: " << stats2.mean() + << "\t Variance: " << stats2.variance() + << "\t Std: " << stats2.std() << std::endl; + } + + return 0; } From 72f53da5a912e10e4bf0c85b96128c1c0e0e0770 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 30 May 2020 11:00:08 -0400 Subject: [PATCH 7/9] added test case --- math/realtime_stats.cpp | 64 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/math/realtime_stats.cpp b/math/realtime_stats.cpp index f853b8274..d2b55a3cd 100644 --- a/math/realtime_stats.cpp +++ b/math/realtime_stats.cpp @@ -6,13 +6,16 @@ * realtime. For example, devices reading biometrics data. The algorithm is * simple enough to be easily implemented in an embedded system. */ +#include #include #include /** * continuous mean and variance computance using - * first value as an approximation for the mean - **/ + * first value as an approximation for the mean. + * If the first number is much far form the mean, the algorithm becomes very + * inaccurate to compute variance and standard deviation. + */ template class stats_computer1 { public: @@ -36,7 +39,9 @@ class stats_computer1 { /** return sample standard deviation computed till last sample */ double std() const { return std::sqrt(this->variance()); } - /** short-hand operator to read new sample from input stream */ + /** short-hand operator to read new sample from input stream + * \n e.g.: `std::cin >> stats1;` + */ friend std::istream &operator>>(std::istream &input, stats_computer1 &stat) { T val; @@ -53,8 +58,8 @@ class stats_computer1 { /** * continuous mean and variance computance using - * Welford's algorithm - **/ + * Welford's algorithm (very accurate) + */ template class stats_computer2 { public: @@ -78,7 +83,9 @@ class stats_computer2 { /** return sample standard deviation computed till last sample */ double std() const { return std::sqrt(this->variance()); } - /** short-hand operator to read new sample from input stream */ + /** short-hand operator to read new sample from input stream + * \n e.g.: `std::cin >> stats1;` + */ friend std::istream &operator>>(std::istream &input, stats_computer2 &stat) { T val; @@ -92,8 +99,53 @@ class stats_computer2 { double mu = 0, var = 0, M = 0; }; +/** Test the algorithm implementation + * \param[in] test_data array of data to test the algorithms + */ +void test_function(const float *test_data, const int number_of_samples) { + float mean = 0.f, variance = 0.f; + + stats_computer1 stats01; + stats_computer2 stats02; + + for (int i = 0; i < number_of_samples; i++) { + stats01.new_val(test_data[i]); + stats02.new_val(test_data[i]); + mean += test_data[i]; + } + + mean /= number_of_samples; + + for (int i = 0; i < number_of_samples; i++) { + float temp = test_data[i] - mean; + variance += temp * temp; + } + variance /= number_of_samples; + + std::cout << "<<<<<<<< Test Function >>>>>>>>" << std::endl + << "Expected: Mean: " << mean << "\t Variance: " << variance + << std::endl; + std::cout << "\tMethod 1:" + << "\tMean: " << stats01.mean() + << "\t Variance: " << stats01.variance() + << "\t Std: " << stats01.std() << std::endl; + std::cout << "\tMethod 2:" + << "\tMean: " << stats02.mean() + << "\t Variance: " << stats02.variance() + << "\t Std: " << stats02.std() << std::endl; + + assert(std::abs(stats01.mean() - mean) < 0.01); + assert(std::abs(stats02.mean() - mean) < 0.01); + assert(std::abs(stats02.variance() - variance) < 0.01); + + std::cout << "(Tests passed)" << std::endl; +} + /** Main function */ int main(int argc, char **argv) { + const float test_data1[] = {3, 4, 5, -1.4, -3.6, 1.9, 1.}; + test_function(test_data1, sizeof(test_data1) / sizeof(test_data1[0])); + std::cout << "Enter data. Any non-numeric data will terminate the data input." << std::endl; From 227c4557928722dd138737315ed9cefb9a62443c Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sat, 30 May 2020 17:16:07 +0000 Subject: [PATCH 8/9] formatting source-code for a850308fbada18c0d4b6f9a9cac5c34fc064cbae --- math/realtime_stats.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/math/realtime_stats.cpp b/math/realtime_stats.cpp index d2b55a3cd..2fbfc9bd5 100644 --- a/math/realtime_stats.cpp +++ b/math/realtime_stats.cpp @@ -23,7 +23,8 @@ class stats_computer1 { * \param[in] x new data sample */ void new_val(T x) { - if (n == 0) K = x; + if (n == 0) + K = x; n++; T tmp = x - K; Ex += tmp; @@ -160,7 +161,8 @@ int main(int argc, char **argv) { // check for failure to read input. Happens for // non-numeric data - if (std::cin.fail()) break; + if (std::cin.fail()) + break; stats1.new_val(val); stats2.new_val(val); From 704e114bd29b0a4436cf9742ed98c419aee17db9 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sat, 30 May 2020 17:16:34 +0000 Subject: [PATCH 9/9] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 21f1a0c61..919fae165 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -122,6 +122,7 @@ * [Prime Factorization](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/prime_factorization.cpp) * [Prime Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/prime_numbers.cpp) * [Primes Up To Billion](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/primes_up_to_billion.cpp) + * [Realtime Stats](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/realtime_stats.cpp) * [Sieve Of Eratosthenes](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/sieve_of_eratosthenes.cpp) * [Sqrt Double](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/sqrt_double.cpp) * [String Fibonacci](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/string_fibonacci.cpp)