summaryrefslogtreecommitdiffstats
path: root/libnetdata/statistical
diff options
context:
space:
mode:
Diffstat (limited to 'libnetdata/statistical')
-rw-r--r--libnetdata/statistical/statistical.c180
-rw-r--r--libnetdata/statistical/statistical.h40
2 files changed, 118 insertions, 102 deletions
diff --git a/libnetdata/statistical/statistical.c b/libnetdata/statistical/statistical.c
index ba8f0c45..ef9fe4e5 100644
--- a/libnetdata/statistical/statistical.c
+++ b/libnetdata/statistical/statistical.c
@@ -2,28 +2,28 @@
#include "../libnetdata.h"
-LONG_DOUBLE default_single_exponential_smoothing_alpha = 0.1;
+NETDATA_DOUBLE default_single_exponential_smoothing_alpha = 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];
+void log_series_to_stderr(NETDATA_DOUBLE *series, size_t entries, NETDATA_DOUBLE result, const char *msg) {
+ const NETDATA_DOUBLE *value, *end = &series[entries];
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, "%" NETDATA_DOUBLE_MODIFIER, *value);
}
- fprintf(stderr, " ] results in " CALCULATED_NUMBER_FORMAT "\n", result);
+ fprintf(stderr, " ] results in " NETDATA_DOUBLE_FORMAT "\n", result);
}
// --------------------------------------------------------------------------------------------------------------------
-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;
+inline NETDATA_DOUBLE sum_and_count(const NETDATA_DOUBLE *series, size_t entries, size_t *count) {
+ const NETDATA_DOUBLE *value, *end = &series[entries];
+ NETDATA_DOUBLE sum = 0;
size_t c = 0;
for(value = series; value < end ; value++) {
- if(calculated_number_isnumber(*value)) {
+ if(netdata_double_isnumber(*value)) {
sum += *value;
c++;
}
@@ -35,42 +35,42 @@ inline LONG_DOUBLE sum_and_count(const LONG_DOUBLE *series, size_t entries, size
return sum;
}
-inline LONG_DOUBLE sum(const LONG_DOUBLE *series, size_t entries) {
+inline NETDATA_DOUBLE sum(const NETDATA_DOUBLE *series, size_t entries) {
return sum_and_count(series, entries, NULL);
}
-inline LONG_DOUBLE average(const LONG_DOUBLE *series, size_t entries) {
+inline NETDATA_DOUBLE average(const NETDATA_DOUBLE *series, size_t entries) {
size_t count = 0;
- LONG_DOUBLE sum = sum_and_count(series, entries, &count);
+ NETDATA_DOUBLE sum = sum_and_count(series, entries, &count);
if(unlikely(!count)) return NAN;
- return sum / (LONG_DOUBLE)count;
+ return sum / (NETDATA_DOUBLE)count;
}
// --------------------------------------------------------------------------------------------------------------------
-LONG_DOUBLE moving_average(const LONG_DOUBLE *series, size_t entries, size_t period) {
+NETDATA_DOUBLE moving_average(const NETDATA_DOUBLE *series, size_t entries, size_t period) {
if(unlikely(period <= 0))
return 0.0;
size_t i, count;
- LONG_DOUBLE sum = 0, avg = 0;
- LONG_DOUBLE p[period];
+ NETDATA_DOUBLE sum = 0, avg = 0;
+ NETDATA_DOUBLE p[period];
for(count = 0; count < period ; count++)
p[count] = 0.0;
for(i = 0, count = 0; i < entries; i++) {
- LONG_DOUBLE value = series[i];
- if(unlikely(!calculated_number_isnumber(value))) continue;
+ NETDATA_DOUBLE value = series[i];
+ if(unlikely(!netdata_double_isnumber(value))) continue;
if(unlikely(count < period)) {
sum += value;
- avg = (count == period - 1) ? sum / (LONG_DOUBLE)period : 0;
+ avg = (count == period - 1) ? sum / (NETDATA_DOUBLE)period : 0;
}
else {
sum = sum - p[count % period] + value;
- avg = sum / (LONG_DOUBLE)period;
+ avg = sum / (NETDATA_DOUBLE)period;
}
p[count % period] = value;
@@ -83,8 +83,8 @@ LONG_DOUBLE moving_average(const LONG_DOUBLE *series, size_t entries, size_t per
// --------------------------------------------------------------------------------------------------------------------
static int qsort_compare(const void *a, const void *b) {
- LONG_DOUBLE *p1 = (LONG_DOUBLE *)a, *p2 = (LONG_DOUBLE *)b;
- LONG_DOUBLE n1 = *p1, n2 = *p2;
+ NETDATA_DOUBLE *p1 = (NETDATA_DOUBLE *)a, *p2 = (NETDATA_DOUBLE *)b;
+ NETDATA_DOUBLE n1 = *p1, n2 = *p2;
if(unlikely(isnan(n1) || isnan(n2))) {
if(isnan(n1) && !isnan(n2)) return -1;
@@ -102,22 +102,22 @@ static int qsort_compare(const void *a, const void *b) {
return 0;
}
-inline void sort_series(LONG_DOUBLE *series, size_t entries) {
- qsort(series, entries, sizeof(LONG_DOUBLE), qsort_compare);
+inline void sort_series(NETDATA_DOUBLE *series, size_t entries) {
+ qsort(series, entries, sizeof(NETDATA_DOUBLE), qsort_compare);
}
-inline LONG_DOUBLE *copy_series(const LONG_DOUBLE *series, size_t entries) {
- LONG_DOUBLE *copy = mallocz(sizeof(LONG_DOUBLE) * entries);
- memcpy(copy, series, sizeof(LONG_DOUBLE) * entries);
+inline NETDATA_DOUBLE *copy_series(const NETDATA_DOUBLE *series, size_t entries) {
+ NETDATA_DOUBLE *copy = mallocz(sizeof(NETDATA_DOUBLE) * entries);
+ memcpy(copy, series, sizeof(NETDATA_DOUBLE) * entries);
return copy;
}
-LONG_DOUBLE median_on_sorted_series(const LONG_DOUBLE *series, size_t entries) {
+NETDATA_DOUBLE median_on_sorted_series(const NETDATA_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;
- LONG_DOUBLE average;
+ NETDATA_DOUBLE average;
if(entries % 2 == 0) {
size_t m = entries / 2;
average = (series[m] + series[m + 1]) / 2;
@@ -129,17 +129,17 @@ LONG_DOUBLE median_on_sorted_series(const LONG_DOUBLE *series, size_t entries) {
return average;
}
-LONG_DOUBLE median(const LONG_DOUBLE *series, size_t entries) {
+NETDATA_DOUBLE median(const NETDATA_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;
- LONG_DOUBLE *copy = copy_series(series, entries);
+ NETDATA_DOUBLE *copy = copy_series(series, entries);
sort_series(copy, entries);
- LONG_DOUBLE avg = median_on_sorted_series(copy, entries);
+ NETDATA_DOUBLE avg = median_on_sorted_series(copy, entries);
freez(copy);
return avg;
@@ -147,18 +147,18 @@ LONG_DOUBLE median(const LONG_DOUBLE *series, size_t entries) {
// --------------------------------------------------------------------------------------------------------------------
-LONG_DOUBLE moving_median(const LONG_DOUBLE *series, size_t entries, size_t period) {
+NETDATA_DOUBLE moving_median(const NETDATA_DOUBLE *series, size_t entries, size_t period) {
if(entries <= period)
return median(series, entries);
- LONG_DOUBLE *data = copy_series(series, entries);
+ NETDATA_DOUBLE *data = copy_series(series, entries);
size_t i;
for(i = period; i < entries; i++) {
data[i - period] = median(&series[i - period], period);
}
- LONG_DOUBLE avg = median(data, entries - period);
+ NETDATA_DOUBLE avg = median(data, entries - period);
freez(data);
return avg;
}
@@ -166,17 +166,17 @@ LONG_DOUBLE moving_median(const LONG_DOUBLE *series, size_t entries, size_t peri
// --------------------------------------------------------------------------------------------------------------------
// http://stackoverflow.com/a/15150143/4525767
-LONG_DOUBLE running_median_estimate(const LONG_DOUBLE *series, size_t entries) {
- LONG_DOUBLE median = 0.0f;
- LONG_DOUBLE average = 0.0f;
+NETDATA_DOUBLE running_median_estimate(const NETDATA_DOUBLE *series, size_t entries) {
+ NETDATA_DOUBLE median = 0.0f;
+ NETDATA_DOUBLE average = 0.0f;
size_t i;
for(i = 0; i < entries ; i++) {
- LONG_DOUBLE value = series[i];
- if(unlikely(!calculated_number_isnumber(value))) continue;
+ NETDATA_DOUBLE value = series[i];
+ if(unlikely(!netdata_double_isnumber(value))) continue;
average += ( value - average ) * 0.1f; // rough running average.
- median += copysignl( average * 0.01, value - median );
+ median += copysignndd( average * 0.01, value - median );
}
return median;
@@ -184,16 +184,16 @@ LONG_DOUBLE running_median_estimate(const LONG_DOUBLE *series, size_t entries) {
// --------------------------------------------------------------------------------------------------------------------
-LONG_DOUBLE standard_deviation(const LONG_DOUBLE *series, size_t entries) {
+NETDATA_DOUBLE standard_deviation(const NETDATA_DOUBLE *series, size_t entries) {
if(unlikely(entries == 0)) return NAN;
if(unlikely(entries == 1)) return series[0];
- const LONG_DOUBLE *value, *end = &series[entries];
+ const NETDATA_DOUBLE *value, *end = &series[entries];
size_t count;
- LONG_DOUBLE sum;
+ NETDATA_DOUBLE sum;
for(count = 0, sum = 0, value = series ; value < end ;value++) {
- if(likely(calculated_number_isnumber(*value))) {
+ if(likely(netdata_double_isnumber(*value))) {
count++;
sum += *value;
}
@@ -202,55 +202,55 @@ LONG_DOUBLE standard_deviation(const LONG_DOUBLE *series, size_t entries) {
if(unlikely(count == 0)) return NAN;
if(unlikely(count == 1)) return sum;
- LONG_DOUBLE average = sum / (LONG_DOUBLE)count;
+ NETDATA_DOUBLE average = sum / (NETDATA_DOUBLE)count;
for(count = 0, sum = 0, value = series ; value < end ;value++) {
- if(calculated_number_isnumber(*value)) {
+ if(netdata_double_isnumber(*value)) {
count++;
- sum += powl(*value - average, 2);
+ sum += powndd(*value - average, 2);
}
}
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);
+ NETDATA_DOUBLE variance = sum / (NETDATA_DOUBLE)(count); // remove -1 from count to have a population stddev
+ NETDATA_DOUBLE stddev = sqrtndd(variance);
return stddev;
}
// --------------------------------------------------------------------------------------------------------------------
-LONG_DOUBLE single_exponential_smoothing(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha) {
+NETDATA_DOUBLE single_exponential_smoothing(const NETDATA_DOUBLE *series, size_t entries, NETDATA_DOUBLE alpha) {
if(unlikely(entries == 0))
return NAN;
if(unlikely(isnan(alpha)))
alpha = default_single_exponential_smoothing_alpha;
- const LONG_DOUBLE *value = series, *end = &series[entries];
- LONG_DOUBLE level = (1.0 - alpha) * (*value);
+ const NETDATA_DOUBLE *value = series, *end = &series[entries];
+ NETDATA_DOUBLE level = (1.0 - alpha) * (*value);
for(value++ ; value < end; value++) {
- if(likely(calculated_number_isnumber(*value)))
+ if(likely(netdata_double_isnumber(*value)))
level = alpha * (*value) + (1.0 - alpha) * level;
}
return level;
}
-LONG_DOUBLE single_exponential_smoothing_reverse(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha) {
+NETDATA_DOUBLE single_exponential_smoothing_reverse(const NETDATA_DOUBLE *series, size_t entries, NETDATA_DOUBLE alpha) {
if(unlikely(entries == 0))
return NAN;
if(unlikely(isnan(alpha)))
alpha = default_single_exponential_smoothing_alpha;
- const LONG_DOUBLE *value = &series[entries -1];
- LONG_DOUBLE level = (1.0 - alpha) * (*value);
+ const NETDATA_DOUBLE *value = &series[entries -1];
+ NETDATA_DOUBLE level = (1.0 - alpha) * (*value);
for(value++ ; value >= series; value--) {
- if(likely(calculated_number_isnumber(*value)))
+ if(likely(netdata_double_isnumber(*value)))
level = alpha * (*value) + (1.0 - alpha) * level;
}
@@ -260,11 +260,14 @@ LONG_DOUBLE single_exponential_smoothing_reverse(const LONG_DOUBLE *series, size
// --------------------------------------------------------------------------------------------------------------------
// 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) {
+NETDATA_DOUBLE double_exponential_smoothing(const NETDATA_DOUBLE *series, size_t entries,
+ NETDATA_DOUBLE alpha,
+ NETDATA_DOUBLE beta,
+ NETDATA_DOUBLE *forecast) {
if(unlikely(entries == 0))
return NAN;
- LONG_DOUBLE level, trend;
+ NETDATA_DOUBLE level, trend;
if(unlikely(isnan(alpha)))
alpha = 0.3;
@@ -279,11 +282,10 @@ LONG_DOUBLE double_exponential_smoothing(const LONG_DOUBLE *series, size_t entri
else
trend = 0;
- const LONG_DOUBLE *value = series;
+ const NETDATA_DOUBLE *value = series;
for(value++ ; value >= series; value--) {
- if(likely(calculated_number_isnumber(*value))) {
-
- LONG_DOUBLE last_level = level;
+ if(likely(netdata_double_isnumber(*value))) {
+ NETDATA_DOUBLE last_level = level;
level = alpha * *value + (1.0 - alpha) * (level + trend);
trend = beta * (level - last_level) + (1.0 - beta) * trend;
@@ -320,24 +322,26 @@ LONG_DOUBLE double_exponential_smoothing(const LONG_DOUBLE *series, size_t entri
* s[t] = γ (Y[t] / a[t]) + (1-γ) s[t-p]
*/
static int __HoltWinters(
- const LONG_DOUBLE *series,
+ const NETDATA_DOUBLE *series,
int entries, // start_time + h
- LONG_DOUBLE alpha, // alpha parameter of Holt-Winters Filter.
- LONG_DOUBLE beta, // beta parameter of Holt-Winters Filter. If set to 0, the function will do exponential smoothing.
- LONG_DOUBLE gamma, // gamma parameter used for the seasonal component. If set to 0, an non-seasonal model is fitted.
+ NETDATA_DOUBLE alpha, // alpha parameter of Holt-Winters Filter.
+ NETDATA_DOUBLE
+ beta, // beta parameter of Holt-Winters Filter. If set to 0, the function will do exponential smoothing.
+ NETDATA_DOUBLE
+ gamma, // gamma parameter used for the seasonal component. If set to 0, an non-seasonal model is fitted.
const int *seasonal,
const int *period,
- const LONG_DOUBLE *a, // Start value for level (a[0]).
- const LONG_DOUBLE *b, // Start value for trend (b[0]).
- LONG_DOUBLE *s, // Vector of start values for the seasonal component (s_1[0] ... s_p[0])
+ const NETDATA_DOUBLE *a, // Start value for level (a[0]).
+ const NETDATA_DOUBLE *b, // Start value for trend (b[0]).
+ NETDATA_DOUBLE *s, // Vector of start values for the seasonal component (s_1[0] ... s_p[0])
/* return values */
- LONG_DOUBLE *SSE, // The final sum of squared errors achieved in optimizing
- LONG_DOUBLE *level, // Estimated values for the level component (size entries - t + 2)
- LONG_DOUBLE *trend, // Estimated values for the trend component (size entries - t + 2)
- LONG_DOUBLE *season // Estimated values for the seasonal component (size entries - t + 2)
+ NETDATA_DOUBLE *SSE, // The final sum of squared errors achieved in optimizing
+ NETDATA_DOUBLE *level, // Estimated values for the level component (size entries - t + 2)
+ NETDATA_DOUBLE *trend, // Estimated values for the trend component (size entries - t + 2)
+ NETDATA_DOUBLE *season // Estimated values for the seasonal component (size entries - t + 2)
)
{
if(unlikely(entries < 4))
@@ -345,13 +349,13 @@ static int __HoltWinters(
int start_time = 2;
- LONG_DOUBLE res = 0, xhat = 0, stmp = 0;
+ NETDATA_DOUBLE res = 0, xhat = 0, stmp = 0;
int i, i0, s0;
/* copy start values to the beginning of the vectors */
level[0] = *a;
if(beta > 0) trend[0] = *b;
- if(gamma > 0) memcpy(season, s, *period * sizeof(LONG_DOUBLE));
+ if(gamma > 0) memcpy(season, s, *period * sizeof(NETDATA_DOUBLE));
for(i = start_time - 1; i < entries; i++) {
/* indices for period i */
@@ -397,7 +401,11 @@ static int __HoltWinters(
return 1;
}
-LONG_DOUBLE holtwinters(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha, LONG_DOUBLE beta, LONG_DOUBLE gamma, LONG_DOUBLE *forecast) {
+NETDATA_DOUBLE holtwinters(const NETDATA_DOUBLE *series, size_t entries,
+ NETDATA_DOUBLE alpha,
+ NETDATA_DOUBLE beta,
+ NETDATA_DOUBLE gamma,
+ NETDATA_DOUBLE *forecast) {
if(unlikely(isnan(alpha)))
alpha = 0.3;
@@ -409,15 +417,15 @@ LONG_DOUBLE holtwinters(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE a
int seasonal = 0;
int period = 0;
- LONG_DOUBLE a0 = series[0];
- LONG_DOUBLE b0 = 0;
- LONG_DOUBLE s[] = {};
+ NETDATA_DOUBLE a0 = series[0];
+ NETDATA_DOUBLE b0 = 0;
+ NETDATA_DOUBLE s[] = {};
- LONG_DOUBLE errors = 0.0;
+ NETDATA_DOUBLE errors = 0.0;
size_t nb_computations = entries;
- LONG_DOUBLE *estimated_level = callocz(nb_computations, sizeof(LONG_DOUBLE));
- LONG_DOUBLE *estimated_trend = callocz(nb_computations, sizeof(LONG_DOUBLE));
- LONG_DOUBLE *estimated_season = callocz(nb_computations, sizeof(LONG_DOUBLE));
+ NETDATA_DOUBLE *estimated_level = callocz(nb_computations, sizeof(NETDATA_DOUBLE));
+ NETDATA_DOUBLE *estimated_trend = callocz(nb_computations, sizeof(NETDATA_DOUBLE));
+ NETDATA_DOUBLE *estimated_season = callocz(nb_computations, sizeof(NETDATA_DOUBLE));
int ret = __HoltWinters(
series,
@@ -436,7 +444,7 @@ LONG_DOUBLE holtwinters(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE a
estimated_season
);
- LONG_DOUBLE value = estimated_level[nb_computations - 1];
+ NETDATA_DOUBLE value = estimated_level[nb_computations - 1];
if(forecast)
*forecast = 0.0;
diff --git a/libnetdata/statistical/statistical.h b/libnetdata/statistical/statistical.h
index bbf241ff..9496e0e7 100644
--- a/libnetdata/statistical/statistical.h
+++ b/libnetdata/statistical/statistical.h
@@ -5,22 +5,30 @@
#include "../libnetdata.h"
-extern void log_series_to_stderr(LONG_DOUBLE *series, size_t entries, calculated_number result, const char *msg);
+extern void log_series_to_stderr(NETDATA_DOUBLE *series, size_t entries, NETDATA_DOUBLE result, const char *msg);
-extern LONG_DOUBLE average(const LONG_DOUBLE *series, size_t entries);
-extern LONG_DOUBLE moving_average(const LONG_DOUBLE *series, size_t entries, size_t period);
-extern LONG_DOUBLE median(const LONG_DOUBLE *series, size_t entries);
-extern LONG_DOUBLE moving_median(const LONG_DOUBLE *series, size_t entries, size_t period);
-extern LONG_DOUBLE running_median_estimate(const LONG_DOUBLE *series, size_t entries);
-extern LONG_DOUBLE standard_deviation(const LONG_DOUBLE *series, size_t entries);
-extern LONG_DOUBLE single_exponential_smoothing(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha);
-extern LONG_DOUBLE single_exponential_smoothing_reverse(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha);
-extern LONG_DOUBLE double_exponential_smoothing(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha, LONG_DOUBLE beta, LONG_DOUBLE *forecast);
-extern LONG_DOUBLE holtwinters(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha, LONG_DOUBLE beta, LONG_DOUBLE gamma, LONG_DOUBLE *forecast);
-extern LONG_DOUBLE sum_and_count(const LONG_DOUBLE *series, size_t entries, size_t *count);
-extern LONG_DOUBLE sum(const LONG_DOUBLE *series, size_t entries);
-extern LONG_DOUBLE median_on_sorted_series(const LONG_DOUBLE *series, size_t entries);
-extern LONG_DOUBLE *copy_series(const LONG_DOUBLE *series, size_t entries);
-extern void sort_series(LONG_DOUBLE *series, size_t entries);
+extern NETDATA_DOUBLE average(const NETDATA_DOUBLE *series, size_t entries);
+extern NETDATA_DOUBLE moving_average(const NETDATA_DOUBLE *series, size_t entries, size_t period);
+extern NETDATA_DOUBLE median(const NETDATA_DOUBLE *series, size_t entries);
+extern NETDATA_DOUBLE moving_median(const NETDATA_DOUBLE *series, size_t entries, size_t period);
+extern NETDATA_DOUBLE running_median_estimate(const NETDATA_DOUBLE *series, size_t entries);
+extern NETDATA_DOUBLE standard_deviation(const NETDATA_DOUBLE *series, size_t entries);
+extern NETDATA_DOUBLE single_exponential_smoothing(const NETDATA_DOUBLE *series, size_t entries, NETDATA_DOUBLE alpha);
+extern NETDATA_DOUBLE
+single_exponential_smoothing_reverse(const NETDATA_DOUBLE *series, size_t entries, NETDATA_DOUBLE alpha);
+extern NETDATA_DOUBLE double_exponential_smoothing(const NETDATA_DOUBLE *series, size_t entries,
+ NETDATA_DOUBLE alpha,
+ NETDATA_DOUBLE beta,
+ NETDATA_DOUBLE *forecast);
+extern NETDATA_DOUBLE holtwinters(const NETDATA_DOUBLE *series, size_t entries,
+ NETDATA_DOUBLE alpha,
+ NETDATA_DOUBLE beta,
+ NETDATA_DOUBLE gamma,
+ NETDATA_DOUBLE *forecast);
+extern NETDATA_DOUBLE sum_and_count(const NETDATA_DOUBLE *series, size_t entries, size_t *count);
+extern NETDATA_DOUBLE sum(const NETDATA_DOUBLE *series, size_t entries);
+extern NETDATA_DOUBLE median_on_sorted_series(const NETDATA_DOUBLE *series, size_t entries);
+extern NETDATA_DOUBLE *copy_series(const NETDATA_DOUBLE *series, size_t entries);
+extern void sort_series(NETDATA_DOUBLE *series, size_t entries);
#endif //NETDATA_STATISTICAL_H