Permalink
Browse files

Add a simple online stats collection.

  • Loading branch information...
1 parent 6d1c6c3 commit b015883ac753a3da7ffa11b0dfbdcbea21a60c7b @zedshaw committed Apr 21, 2012
Showing with 155 additions and 0 deletions.
  1. +59 −0 src/lcthw/stats.c
  2. +24 −0 src/lcthw/stats.h
  3. +72 −0 tests/stats_tests.c
View
@@ -0,0 +1,59 @@
+#include <math.h>
+#include <lcthw/stats.h>
+#include <stdlib.h>
+#include <lcthw/dbg.h>
+
+Stats *Stats_recreate(double sum, double sumsq, unsigned long n, double min, double max)
+{
+ Stats *st = malloc(sizeof(Stats));
+ check_mem(st);
+
+ st->sum = sum;
+ st->sumsq = sumsq;
+ st->n = n;
+ st->min = min;
+ st->max = max;
+
+ return st;
+
+error:
+ return NULL;
+}
+
+Stats *Stats_create()
+{
+ return Stats_recreate(0.0, 0.0, 0L, 0.0, 0.0);
+}
+
+double Stats_mean(Stats *st)
+{
+ return st->sum / st->n;
+}
+
+double Stats_stddev(Stats *st)
+{
+ return sqrt( (st->sumsq - ( st->sum * st->sum / st->n)) / (st->n - 1) );
+}
+
+void Stats_sample(Stats *st, double s)
+{
+ st->sum += s;
+ st->sumsq += s * s;
+
+ if(st->n == 0) {
+ st->min = s;
+ st->max = s;
+ } else {
+ if(st->min > s) st->min = s;
+ if(st->max < s) st->max = s;
+ }
+
+ st->n += 1;
+}
+
+void Stats_dump(Stats *st)
+{
+ fprintf(stderr, "sum: %f, sumsq: %f, n: %ld, min: %f, max: %f, mean: %f, stddev: %f",
+ st->sum, st->sumsq, st->n, st->min, st->max,
+ Stats_mean(st), Stats_stddev(st));
+}
View
@@ -0,0 +1,24 @@
+#ifndef lcthw_stats_h
+#define lctwh_stats_h
+
+typedef struct Stats {
+ double sum;
+ double sumsq;
+ unsigned long n;
+ double min;
+ double max;
+} Stats;
+
+Stats *Stats_recreate(double sum, double sumsq, unsigned long n, double min, double max);
+
+Stats *Stats_create();
+
+double Stats_mean(Stats *st);
+
+double Stats_stddev(Stats *st);
+
+void Stats_sample(Stats *st, double s);
+
+void Stats_dump(Stats *st);
+
+#endif
View
@@ -0,0 +1,72 @@
+#include "minunit.h"
+#include <lcthw/stats.h>
+#include <math.h>
+
+const int NUM_SAMPLES = 10;
+double samples[] = {
+ 6.1061334, 9.6783204, 1.2747090, 8.2395131, 0.3333483,
+ 6.9755066, 1.0626275, 7.6587523, 4.9382973, 9.5788115
+};
+
+Stats expect = {
+ .sumsq = 425.1641,
+ .sum = 55.84602,
+ .min = 0.333,
+ .max = 9.678,
+ .n = 10,
+};
+double expect_mean = 5.584602;
+double expect_stddev = 3.547868;
+
+#define EQ(X,Y,N) (round((X) * pow(10, N)) == round((Y) * pow(10, N)))
+
+char *test_operations()
+{
+ int i = 0;
+ Stats *st = Stats_create();
+ mu_assert(st != NULL, "Failed to create stats.");
+
+ for(i = 0; i < NUM_SAMPLES; i++) {
+ Stats_sample(st, samples[i]);
+ }
+
+ Stats_dump(st);
+
+ mu_assert(EQ(st->sumsq, expect.sumsq, 3), "sumsq not valid");
+ mu_assert(EQ(st->sum, expect.sum, 3), "sum not valid");
+ mu_assert(EQ(st->min, expect.min, 3), "min not valid");
+ mu_assert(EQ(st->max, expect.max, 3), "max not valid");
+ mu_assert(EQ(st->n, expect.n, 3), "max not valid");
+ mu_assert(EQ(expect_mean, Stats_mean(st), 3), "mean not valid");
+ mu_assert(EQ(expect_stddev, Stats_stddev(st), 3), "stddev not valid");
+
+ return NULL;
+}
+
+char *test_recreate()
+{
+ Stats *st = Stats_recreate(expect.sum, expect.sumsq, expect.n, expect.min, expect.max);
+
+ mu_assert(st->sum == expect.sum, "sum not equal");
+ mu_assert(st->sumsq == expect.sumsq, "sumsq not equal");
+ mu_assert(st->n == expect.n, "n not equal");
+ mu_assert(st->min == expect.min, "min not equal");
+ mu_assert(st->max == expect.max, "max not equal");
+ mu_assert(EQ(expect_mean, Stats_mean(st), 3), "mean not valid");
+ mu_assert(EQ(expect_stddev, Stats_stddev(st), 3), "stddev not valid");
+
+ return NULL;
+}
+
+char *all_tests()
+{
+ mu_suite_start();
+
+ mu_run_test(test_operations);
+ mu_run_test(test_recreate);
+
+ return NULL;
+}
+
+RUN_TESTS(all_tests);
+

0 comments on commit b015883

Please sign in to comment.