summaryrefslogtreecommitdiffstats
path: root/libnetdata/statistical/statistical.c
diff options
context:
space:
mode:
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)