Skip to content

Statistics Calculator — C source

Compute descriptive statistics - count, sum, mean, median, mode, min/max, range, variance, standard deviation, and quartiles (Q1/Q3/IQR) - from any list of numbers. Tolerates mixed separators and flags unparseable tokens. Choose sample (n−1) or population (n) variance. Everything runs 100% client-side.

This is the C implementation — the same logic the interactive tool runs, in a shareable, citable form.

/* statistics — descriptive statistics over a free-form number list. Language: C (C11). Port of src/lib/statistics.ts — same logic as this dir's python.py: comma/whitespace parse (finite only), R-7 interpolated quantiles, mode (empty when uniform), sample vs population variance. */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int cmp_double(const void *a, const void *b) { double x = *(const double *)a, y = *(const double *)b; return x < y ? -1 : x > y; }

/* Split on comma/whitespace runs; only fully-parsed finite tokens count as values. */
static void parse_numbers(const char *input, double **vals, size_t *n, char ***inv, size_t *n_inv)
{
    size_t cap = 16;
    *vals = malloc(cap * sizeof **vals); /* grown by realloc below */
    *inv = NULL; *n = *n_inv = 0;
    char *copy = malloc(strlen(input) + 1); /* kept alive: invalid[] points into it */
    strcpy(copy, input);
    for (char *tok = strtok(copy, " ,\t\n\r"); tok; tok = strtok(NULL, " ,\t\n\r")) {
        char *end = NULL;
        double v = strtod(tok, &end); /* accepts inf/nan — filtered by isfinite */
        if (end != tok && *end == '\0' && isfinite(v)) {
            if (*n == cap) *vals = realloc(*vals, (cap *= 2) * sizeof **vals);
            (*vals)[(*n)++] = v;
        } else {
            *inv = realloc(*inv, (*n_inv + 1) * sizeof **inv);
            (*inv)[(*n_inv)++] = tok;
        }
    }
}

/* Linear-interpolation quantile (R-7 / NumPy / Excel PERCENTILE) over ascending, non-empty data. */
static double quantile(const double *s, size_t n, double p)
{
    double h = (double)(n - 1) * p;
    size_t lo = (size_t)floor(h), hi = (size_t)ceil(h);
    return lo == hi ? s[lo] : s[lo] + (h - lo) * (s[hi] - s[lo]);
}

/* Mode over an ascending array (equal runs are contiguous): one distinct value IS the mode; uniform spread → none. */
static size_t mode_sorted(const double *s, size_t n, double *out)
{
    size_t best = 1, runs = 0, m = 0, i = 0, at_best = 0;
    for (; i < n; runs++) { /* pass 1: longest run of equal neighbours */
        size_t j = i;
        while (j < n && s[j] == s[i]) j++;
        if (j - i > best) best = j - i;
        i = j;
    }
    if (runs == 1) { out[0] = s[0]; return 1; }
    for (i = 0; i < n;) { /* pass 2: emit each run whose length hits the max */
        size_t j = i;
        while (j < n && s[j] == s[i]) j++;
        if (j - i == best) out[m++] = s[i], at_best++;
        i = j;
    }
    return at_best == runs ? 0 : m;
}

int main(void)
{
    double *vals, *s, modes[64], sum = 0, ss = 0;
    char **inv;
    size_t n, n_inv, m, i;
    parse_numbers("2, 4 4, 6, 8, 11, oops", &vals, &n, &inv, &n_inv);
    s = malloc(n * sizeof *s); /* sorted copy — the input order stays intact */
    memcpy(s, vals, n * sizeof *s);
    qsort(s, n, sizeof *s, cmp_double);
    for (i = 0; i < n; i++) sum += vals[i]; /* sum in original order */
    double mean = sum / n;
    for (i = 0; i < n; i++) ss += (vals[i] - mean) * (vals[i] - mean);
    double variance = n >= 2 ? ss / (n - 1) : NAN; /* sample estimator; population is ss / n */
    double q1 = quantile(s, n, 0.25), med = quantile(s, n, 0.5), q3 = quantile(s, n, 0.75);
    m = mode_sorted(s, n, modes);
    printf("n=%zu sum=%g mean=%g\nmedian=%g q1=%g q3=%g iqr=%g\nmin=%g max=%g range=%g\nvariance(sample)=%g stddev=%g\nmode=[",
           n, sum, mean, med, q1, q3, q3 - q1, s[0], s[n - 1], s[n - 1] - s[0], variance, sqrt(variance));
    for (i = 0; i < m; i++) printf("%s%g", i ? ", " : "", modes[i]);
    printf("]  invalid=[");
    for (i = 0; i < n_inv; i++) printf("%s%s", i ? ", " : "", inv[i]);
    printf("]\n");
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →