diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2018-11-07 12:19:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2018-11-07 12:20:17 +0000 |
commit | a64a253794ac64cb40befee54db53bde17dd0d49 (patch) | |
tree | c1024acc5f6e508814b944d99f112259bb28b1be /libnetdata/statistical/statistical.c | |
parent | New upstream version 1.10.0+dfsg (diff) | |
download | netdata-a64a253794ac64cb40befee54db53bde17dd0d49.tar.xz netdata-a64a253794ac64cb40befee54db53bde17dd0d49.zip |
New upstream version 1.11.0+dfsgupstream/1.11.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | libnetdata/statistical/statistical.c (renamed from src/statistical.c) | 193 |
1 files changed, 93 insertions, 100 deletions
diff --git a/src/statistical.c b/libnetdata/statistical/statistical.c index d4b33fd5a..15792fd15 100644 --- a/src/statistical.c +++ b/libnetdata/statistical/statistical.c @@ -1,37 +1,36 @@ -#include "common.h" +// SPDX-License-Identifier: GPL-3.0-or-later -// -------------------------------------------------------------------------------------------------------------------- - -inline LONG_DOUBLE sum_and_count(const LONG_DOUBLE *series, size_t entries, size_t *count) { - if(unlikely(entries == 0)) { - if(likely(count)) - *count = 0; +#include "../libnetdata.h" - return NAN; - } +LONG_DOUBLE default_single_exponential_smoothing_alpha = 0.1; - if(unlikely(entries == 1)) { - if(likely(count)) - *count = (isnan(series[0])?0:1); +void log_series_to_stderr(LONG_DOUBLE *series, size_t entries, calculated_number result, const char *msg) { + const LONG_DOUBLE *value, *end = &series[entries]; - return series[0]; + fprintf(stderr, "%s of %zu entries [ ", msg, entries); + for(value = series; value < end ;value++) { + if(value != series) fprintf(stderr, ", "); + fprintf(stderr, "%" LONG_DOUBLE_MODIFIER, *value); } + fprintf(stderr, " ] results in " CALCULATED_NUMBER_FORMAT "\n", result); +} + +// -------------------------------------------------------------------------------------------------------------------- - size_t i, c = 0; +inline LONG_DOUBLE sum_and_count(const LONG_DOUBLE *series, size_t entries, size_t *count) { + const LONG_DOUBLE *value, *end = &series[entries]; LONG_DOUBLE sum = 0; + size_t c = 0; - for(i = 0; i < entries ; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; - c++; - sum += value; + for(value = series; value < end ; value++) { + if(isnormal(*value)) { + sum += *value; + c++; + } } - if(likely(count)) - *count = c; - - if(unlikely(c == 0)) - return NAN; + if(unlikely(!c)) sum = NAN; + if(likely(count)) *count = c; return sum; } @@ -44,9 +43,7 @@ inline LONG_DOUBLE average(const LONG_DOUBLE *series, size_t entries) { size_t count = 0; LONG_DOUBLE sum = sum_and_count(series, entries, &count); - if(unlikely(count == 0)) - return NAN; - + if(unlikely(!count)) return NAN; return sum / (LONG_DOUBLE)count; } @@ -65,7 +62,7 @@ LONG_DOUBLE moving_average(const LONG_DOUBLE *series, size_t entries, size_t per for(i = 0, count = 0; i < entries; i++) { LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; + if(unlikely(!isnormal(value))) continue; if(unlikely(count < period)) { sum += value; @@ -116,33 +113,25 @@ inline LONG_DOUBLE *copy_series(const LONG_DOUBLE *series, size_t entries) { } LONG_DOUBLE median_on_sorted_series(const LONG_DOUBLE *series, size_t entries) { - if(unlikely(entries == 0)) - return NAN; - - if(unlikely(entries == 1)) - return series[0]; - - if(unlikely(entries == 2)) - return (series[0] + series[1]) / 2; + if(unlikely(entries == 0)) return NAN; + if(unlikely(entries == 1)) return series[0]; + if(unlikely(entries == 2)) return (series[0] + series[1]) / 2; - LONG_DOUBLE avg; + LONG_DOUBLE average; if(entries % 2 == 0) { size_t m = entries / 2; - avg = (series[m] + series[m + 1]) / 2; + average = (series[m] + series[m + 1]) / 2; } else { - avg = series[entries / 2]; + average = series[entries / 2]; } - return avg; + return average; } LONG_DOUBLE median(const LONG_DOUBLE *series, size_t entries) { - if(unlikely(entries == 0)) - return NAN; - - if(unlikely(entries == 1)) - return series[0]; + if(unlikely(entries == 0)) return NAN; + if(unlikely(entries == 1)) return series[0]; if(unlikely(entries == 2)) return (series[0] + series[1]) / 2; @@ -184,7 +173,7 @@ LONG_DOUBLE running_median_estimate(const LONG_DOUBLE *series, size_t entries) { for(i = 0; i < entries ; i++) { LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; + if(unlikely(!isnormal(value))) continue; average += ( value - average ) * 0.1f; // rough running average. median += copysignl( average * 0.01, value - median ); @@ -196,47 +185,36 @@ LONG_DOUBLE running_median_estimate(const LONG_DOUBLE *series, size_t entries) { // -------------------------------------------------------------------------------------------------------------------- LONG_DOUBLE standard_deviation(const LONG_DOUBLE *series, size_t entries) { - if(unlikely(entries < 1)) - return NAN; - - if(unlikely(entries == 1)) - return series[0]; - - size_t i, count = 0; - LONG_DOUBLE sum = 0; + if(unlikely(entries == 0)) return NAN; + if(unlikely(entries == 1)) return series[0]; - for(i = 0; i < entries ; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; + const LONG_DOUBLE *value, *end = &series[entries]; + size_t count; + LONG_DOUBLE sum; - count++; - sum += value; + for(count = 0, sum = 0, value = series ; value < end ;value++) { + if(likely(isnormal(*value))) { + count++; + sum += *value; + } } - if(unlikely(count == 0)) - return NAN; - - if(unlikely(count == 1)) - return sum; + if(unlikely(count == 0)) return NAN; + if(unlikely(count == 1)) return sum; LONG_DOUBLE average = sum / (LONG_DOUBLE)count; - for(i = 0, count = 0, sum = 0; i < entries ; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; - - count++; - sum += powl(value - average, 2); + for(count = 0, sum = 0, value = series ; value < end ;value++) { + if(isnormal(*value)) { + count++; + sum += powl(*value - average, 2); + } } - if(unlikely(count == 0)) - return NAN; - - if(unlikely(count == 1)) - return average; - - LONG_DOUBLE variance = sum / (LONG_DOUBLE)(count - 1); // remove -1 to have a population stddev + if(unlikely(count == 0)) return NAN; + if(unlikely(count == 1)) return average; + LONG_DOUBLE variance = sum / (LONG_DOUBLE)(count); // remove -1 from count to have a population stddev LONG_DOUBLE stddev = sqrtl(variance); return stddev; } @@ -244,21 +222,36 @@ LONG_DOUBLE standard_deviation(const LONG_DOUBLE *series, size_t entries) { // -------------------------------------------------------------------------------------------------------------------- LONG_DOUBLE single_exponential_smoothing(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha) { - size_t i, count = 0; - LONG_DOUBLE level = 0, sum = 0; + if(unlikely(entries == 0)) + return NAN; if(unlikely(isnan(alpha))) - alpha = 0.3; + alpha = default_single_exponential_smoothing_alpha; - for(i = 0; i < entries ; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; - count++; + const LONG_DOUBLE *value = series, *end = &series[entries]; + LONG_DOUBLE level = (1.0 - alpha) * (*value); + + for(value++ ; value < end; value++) { + if(likely(isnormal(*value))) + level = alpha * (*value) + (1.0 - alpha) * level; + } - sum += value; + return level; +} + +LONG_DOUBLE single_exponential_smoothing_reverse(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha) { + if(unlikely(entries == 0)) + return NAN; - LONG_DOUBLE last_level = level; - level = alpha * value + (1.0 - alpha) * last_level; + if(unlikely(isnan(alpha))) + alpha = default_single_exponential_smoothing_alpha; + + const LONG_DOUBLE *value = &series[entries -1]; + LONG_DOUBLE level = (1.0 - alpha) * (*value); + + for(value++ ; value >= series; value--) { + if(likely(isnormal(*value))) + level = alpha * (*value) + (1.0 - alpha) * level; } return level; @@ -268,8 +261,10 @@ LONG_DOUBLE single_exponential_smoothing(const LONG_DOUBLE *series, size_t entri // http://grisha.org/blog/2016/02/16/triple-exponential-smoothing-forecasting-part-ii/ LONG_DOUBLE double_exponential_smoothing(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha, LONG_DOUBLE beta, LONG_DOUBLE *forecast) { - size_t i, count = 0; - LONG_DOUBLE level = series[0], trend, sum; + if(unlikely(entries == 0)) + return NAN; + + LONG_DOUBLE level, trend; if(unlikely(isnan(alpha))) alpha = 0.3; @@ -277,24 +272,22 @@ LONG_DOUBLE double_exponential_smoothing(const LONG_DOUBLE *series, size_t entri if(unlikely(isnan(beta))) beta = 0.05; + level = series[0]; + if(likely(entries > 1)) trend = series[1] - series[0]; else trend = 0; - sum = series[0]; - - for(i = 1; i < entries ; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; - count++; + const LONG_DOUBLE *value = series; + for(value++ ; value >= series; value--) { + if(likely(isnormal(*value))) { - sum += value; + LONG_DOUBLE last_level = level; + level = alpha * *value + (1.0 - alpha) * (level + trend); + trend = beta * (level - last_level) + (1.0 - beta) * trend; - LONG_DOUBLE last_level = level; - - level = alpha * value + (1.0 - alpha) * (level + trend); - trend = beta * (level - last_level) + (1.0 - beta) * trend; + } } if(forecast) |