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++ (20). 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 <algorithm>
#include <cmath>
#include <iostream>
#include <limits>
#include <map>
#include <sstream>
#include <string>
#include <vector>

struct ParseResult { std::vector<double> values; std::vector<std::string> invalid; };
struct Stats { int count; double sum, mean, median, min, max, range, variance, stddev, q1, q3, iqr; std::vector<double> mode; };
constexpr double kNaN = std::numeric_limits<double>::quiet_NaN();
/* Split on comma/whitespace runs; only fully-parsed finite tokens count as values. */
static ParseResult parseNumbers(const std::string &input)
{
    ParseResult r;
    std::string s = input;
    std::replace(s.begin(), s.end(), ',', ' ');
    std::istringstream in(s);
    std::string tok;
    while (in >> tok) {
        try {
            size_t pos = 0;
            double v = std::stod(tok, &pos); /* accepts inf/nan — filtered by isfinite */
            if (pos == tok.size() && std::isfinite(v)) r.values.push_back(v);
            else r.invalid.push_back(tok);
        } catch (const std::exception &) { r.invalid.push_back(tok); } /* not a number at all */
    }
    return r;
}
/* Linear-interpolation quantile (R-7 / NumPy / Excel PERCENTILE) over ascending, non-empty data. */
static double quantile(const std::vector<double> &s, double p)
{
    double h = (s.size() - 1) * p;
    size_t lo = (size_t)std::floor(h), hi = (size_t)std::ceil(h);
    return lo == hi ? s[lo] : s[lo] + (h - lo) * (s[hi] - s[lo]);
}

/* Most frequent value(s), ascending; empty when every distinct value ties (uniform). */
static std::vector<double> computeMode(const std::vector<double> &values)
{
    std::map<double, int> freq; /* ordered keys → modes come out ascending */
    for (double v : values) freq[v]++;
    if (freq.size() == 1) return { values[0] };
    int best = 0;
    for (const auto &[v, c] : freq) best = std::max(best, c);
    std::vector<double> modes;
    for (const auto &[v, c] : freq)
        if (c == best) modes.push_back(v);
    return modes.size() == freq.size() ? std::vector<double>{} : modes;
}
static Stats summarize(const std::vector<double> &values, bool sample = true)
{
    if (values.empty()) return { 0, kNaN, kNaN, kNaN, kNaN, kNaN, kNaN, kNaN, kNaN, kNaN, kNaN, kNaN, {} };
    std::vector<double> s = values;
    std::sort(s.begin(), s.end());
    double sum = 0;
    for (double v : values) sum += v; /* sum in original order */
    double mean = sum / values.size(), ss = 0;
    for (double v : values) ss += (v - mean) * (v - mean);
    double variance = !sample ? ss / values.size()
                              : values.size() >= 2 ? ss / (values.size() - 1) : kNaN; /* population vs sample */
    double q1 = quantile(s, 0.25), med = quantile(s, 0.5), q3 = quantile(s, 0.75);
    return { (int)values.size(), sum, mean, med, s.front(), s.back(), s.back() - s.front(),
             variance, std::sqrt(variance), q1, q3, q3 - q1, computeMode(values) };
}
int main()
{
    auto [values, invalid] = parseNumbers("2, 4 4, 6, 8, 11, oops");
    Stats st = summarize(values); /* sample=true — population: summarize(values, false) */
    std::cout << "n=" << st.count << " sum=" << st.sum << " mean=" << st.mean
              << "\nmedian=" << st.median << " q1=" << st.q1 << " q3=" << st.q3 << " iqr=" << st.iqr
              << "\nmin=" << st.min << " max=" << st.max << " range=" << st.range
              << "\nvariance(sample)=" << st.variance << " stddev=" << st.stddev << "\nmode=[";
    for (size_t i = 0; i < st.mode.size(); i++) std::cout << (i ? ", " : "") << st.mode[i];
    std::cout << "]  invalid=[";
    for (size_t i = 0; i < invalid.size(); i++) std::cout << (i ? ", " : "") << invalid[i];
    std::cout << "]\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 →