Commit d5e0a290 authored by Steffen Vogel's avatar Steffen Vogel 🎅🏼

hist: use more C++ constructs

parent 39e23fc9
......@@ -23,8 +23,7 @@
#pragma once
#include <cstdio>
#include <cstdint>
#include <vector>
#include <jansson.h>
......@@ -38,13 +37,11 @@ class Hist {
public:
using cnt_t = uintmax_t;
using idx_t = std::vector<cnt_t>::difference_type;
/** Initialize struct hist with supplied values and allocate memory for buckets. */
Hist(int buckets = 0, cnt_t warmup = 0);
/** Free the dynamically allocated memory. */
~Hist();
/** Reset all counters and values back to zero. */
void reset();
......@@ -121,8 +118,6 @@ protected:
double lowest; /**< The lowest value observed (may be lower than #low). */
double last; /**< The last value which has been put into the buckets */
int length; /**< The number of buckets in #data. */
cnt_t total; /**< Total number of counted values. */
cnt_t warmup; /**< Number of values which are used during warmup phase. */
......@@ -130,7 +125,7 @@ protected:
cnt_t lower; /**< The number of values which are lower than #low. */
cnt_t *data; /**< Pointer to dynamically allocated array of size length. */
std::vector<cnt_t> data; /**< Bucket counters. */
double _m[2], _s[2]; /**< Private variables for online variance calculation */
};
......
......@@ -20,12 +20,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <float.h>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <villas/utils.hpp>
#include <villas/hist.hpp>
......@@ -36,21 +32,10 @@ using namespace villas::utils;
namespace villas {
Hist::Hist(int buckets, Hist::cnt_t wu)
{
length = buckets;
warmup = wu;
data = (Hist::cnt_t *) (buckets ? alloc(length * sizeof(Hist::cnt_t)) : nullptr);
Hist::reset();
}
Hist::~Hist()
{
if (data)
free(data);
}
Hist::Hist(int buckets, Hist::cnt_t wu) :
warmup(wu),
data(buckets)
{ }
void Hist::put(double value)
{
......@@ -62,24 +47,26 @@ void Hist::put(double value)
if (value < lowest)
lowest = value;
if (total < warmup) {
}
else if (total == warmup) {
low = getMean() - 3 * getStddev();
high = getMean() + 3 * getStddev();
resolution = (high - low) / length;
}
else {
int idx = round((value - low) / resolution);
/* Check bounds and increment */
if (idx >= length)
higher++;
else if (idx < 0)
lower++;
else if (data != nullptr)
data[idx]++;
if (data.size()) {
if (total < warmup) {
/* We are still in warmup phase... Waiting for more samples... */
}
else if (data.size() && total == warmup) {
low = getMean() - 3 * getStddev();
high = getMean() + 3 * getStddev();
resolution = (high - low) / data.size();
}
else {
idx_t idx = std::round((value - low) / resolution);
/* Check bounds and increment */
if (idx >= (idx_t) data.size())
higher++;
else if (idx < 0)
lower++;
else
data[idx]++;
}
}
total++;
......@@ -107,21 +94,21 @@ void Hist::reset()
higher = 0;
lower = 0;
highest = -DBL_MAX;
lowest = DBL_MAX;
highest = std::numeric_limits<double>::min();
lowest = std::numeric_limits<double>::max();
if (data)
memset(data, 0, length * sizeof(unsigned));
for (auto &elm : data)
elm = 0;
}
double Hist::getMean() const
{
return (total > 0) ? _m[0] : NAN;
return total > 0 ? _m[0] : std::numeric_limits<double>::quiet_NaN();
}
double Hist::getVar() const
{
return (total > 1) ? _s[0] / (total - 1) : NAN;
return total > 1 ? _s[0] / (total - 1) : std::numeric_limits<double>::quiet_NaN();
}
double Hist::getStddev() const
......@@ -156,13 +143,8 @@ void Hist::print(bool details) const
void Hist::plot() const
{
Hist::cnt_t max = 1;
/* Get highest bar */
for (int i = 0; i < length; i++) {
if (data[i] > max)
max = data[i];
}
Hist::cnt_t max = *std::max_element(data.begin(), data.end());
std::vector<TableColumn> cols = {
{ -9, TableColumn::Alignment::RIGHT, "Value", "%+9.3g" },
......@@ -175,7 +157,7 @@ void Hist::plot() const
/* Print plot */
table.header();
for (int i = 0; i < length; i++) {
for (size_t i = 0; i < data.size(); i++) {
double value = low + (i) * resolution;
Hist::cnt_t cnt = data[i];
int bar = cols[2].getWidth() * ((double) cnt / max);
......@@ -196,8 +178,8 @@ char * Hist::dump() const
strcatf(&buf, "[ ");
for (int i = 0; i < length; i++)
strcatf(&buf, "%ju ", data[i]);
for (auto elm : data)
strcatf(&buf, "%ju ", elm);
strcatf(&buf, "]");
......@@ -229,8 +211,8 @@ json_t * Hist::toJson() const
if (total - lower - higher > 0) {
json_buckets = json_array();
for (int i = 0; i < length; i++)
json_array_append(json_buckets, json_integer(data[i]));
for (auto elm : data)
json_array_append(json_buckets, json_integer(elm));
json_object_set(json_hist, "buckets", json_buckets);
}
......@@ -269,7 +251,7 @@ int Hist::dumpMatlab(FILE *f) const
free(buf);
}
else
fprintf(f, "'buckets', zeros(1, %d)", length);
fprintf(f, "'buckets', zeros(1, %zu)", data.size());
fprintf(f, ")");
......
......@@ -20,12 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <array>
#include <criterion/criterion.h>
#include <villas/hist.hpp>
#include <villas/utils.hpp>
const double test_data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
const std::array<double, 10> test_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
using namespace villas;
......@@ -35,10 +37,10 @@ Test(hist, simple) {
Hist h;
for (unsigned i = 0; i < ARRAY_LEN(test_data); i++)
h.put(test_data[i]);
for (auto td : test_data)
h.put(td);
cr_assert_float_eq(h.getMean(), 5.5, 1e-6);
cr_assert_float_eq(h.getMean(), 5.5, 1e-6, "Mean is %lf", h.getMean());
cr_assert_float_eq(h.getVar(), 9.1666, 1e-3,);
cr_assert_float_eq(h.getStddev(), 3.027650, 1e-6);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment