Languages: English · Português (Brasil)
A small statistics library for C11 with no dependencies beyond the C standard library. The API is modeled on Python's statistics module, and the test suite checks results against reference values computed with it.
Status: early-stage personal project (v0.1.0). It has unit tests and CI, plus a small micro-benchmark measured on a single machine. There is no known production use.
| Area | Functions |
|---|---|
| Central tendency | mean, mode, multimode, median, median_low, median_high, median_grouped |
| Other means | harmonic_mean, geometric_mean, weighted_mean, trimmed_mean |
| Quantiles | quantile, quantiles (linear interpolation, same as Python's inclusive method) |
| Dispersion | variance, pvariance, stdev, pstdev, range, iqr, mad |
| Shape | skewness, kurtosis (population moments; kurtosis is excess kurtosis) |
| Relationships | covariance, correlation (Pearson), spearman |
| Regression | linear_regression, linear_regression_full (slope, intercept, R², residual variance) |
| Distributions | Normal (pdf, cdf, inv_cdf), Binomial and Poisson (pmf, cdf) |
| Streaming | cstats_accumulator: Welford's algorithm for count, mean, variance, min and max, with merge to combine partial results; no heap allocation |
All functions are prefixed with cstats_. The full, documented API is in include/cstats.h.
#include <stdio.h>
#include <cstats.h>
int main(void) {
double x[] = {1.0, 2.0, 3.0, 4.0, 5.0};
double y[] = {2.1, 3.9, 6.2, 8.1, 10.5};
double slope, intercept, r_squared, residual_var;
printf("mean = %.2f, stdev = %.4f\n", cstats_mean(x, 5), cstats_stdev(x, 5));
if (cstats_linear_regression_full(x, y, 5, &slope, &intercept,
&r_squared, &residual_var) == 0) {
printf("y = %.2fx + %.2f (R² = %.4f)\n", slope, intercept, r_squared);
}
return 0;
}Streaming statistics without storing the data:
cstats_accumulator acc;
cstats_accumulator_init(&acc);
for (int i = 1; i <= 100; i++) cstats_accumulator_add(&acc, i);
printf("n=%zu mean=%.2f stdev=%.4f\n", cstats_accumulator_count(&acc),
cstats_accumulator_mean(&acc), cstats_accumulator_stdev(&acc));Requires a C11 compiler (GCC, Clang or MSVC) and CMake 3.16+.
cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure
cmake --install build # may need sudoOptions: -DSTATS_BUILD_TESTS=ON|OFF (default ON) and -DSTATS_BUILD_SHARED=ON|OFF (default OFF).
Using it from another CMake project after installing:
find_package(cstats REQUIRED)
target_link_libraries(my_app PRIVATE cstats::cstats)- Functions returning
doublereturnNANon invalid input (NULLpointer, too few samples, parameter outside its domain) or when memory allocation fails. - Functions returning
intreturn0on success and-1on error. cstats_multimodereturns the total number of modes (likesnprintf); only the firstmax_modesare written.- NaN in the data: functions that sort (median, mode, multimode, quantiles, grouped median, MAD, trimmed mean, Spearman) return
NAN/-1, because ordering with NaN is undefined. Plain accumulations (mean, variance, covariance) propagate NaN per IEEE 754.cstats_accumulator_addrejects NaN without changing its state. cstats_linear_regression_fullreturns aNANresidual variance whensize == 2.
- No global state: functions can be called from several threads on different data. This has not been verified with ThreadSanitizer.
- Functions that need ordering copy the input (
malloc) and sort the copy withqsort, so the caller's array is never modified. They are O(n log n) and allocate. For streaming or allocation-free use, use the accumulator. - Sums are plain
doubleaccumulation, without compensated (Kahan) summation. - The public API is annotated with
CSTATS_API, so the shared library exports symbols on Windows.
tests/test_main.cis a dependency-free test runner (150 checks). Expected values come from Python'sstatistics,mathandNormalDist.- Edge cases covered:
NULLand empty input, single samples, NaN in data, non-positive values in harmonic/geometric means, constantxin regression,size == 2residual variance, a too-smallmultimodebuffer, out-of-domain distribution parameters, and agreement between the accumulator (including aftermerge) and the batch functions. - GitHub Actions builds with warnings as errors (
-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wdouble-promotion, or/W4on MSVC) on Linux (GCC, Clang), macOS (Clang) and Windows (MSVC), and runs one job under AddressSanitizer and UBSan. - Locally verified with GCC (MinGW) and Clang on Windows;
find_package(cstats)was checked with a separate consumer project.
bench/bench.c times each function on pseudo-random data (best of 5 runs). Build and run it with:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DSTATS_BUILD_BENCH=ON
cmake --build build
./build/cstats_bench 1000000One run on a Windows machine, GCC 16.2 (MinGW-w64, -O3), n = 1,000,000 (clock() has about 1 ms resolution here, so the small values are approximate):
| Function | Time |
|---|---|
mean |
~1 ms |
variance |
~2 ms |
correlation (Pearson) |
~2 ms |
median (sorts a copy) |
~275 ms |
quantile (sorts a copy) |
~263 ms |
mad (two sorts) |
~548 ms |
spearman (n = 100,000) |
~54 ms |
accumulator add × n + stdev |
~16 ms |
These numbers come from one machine and one compiler; they are meant to show relative cost, not absolute speed. The main takeaway: anything that sorts is roughly two orders of magnitude slower than a single pass, so median and quantile would benefit from a selection algorithm (see below).
- No hypothesis tests (t-test, chi-square, Kolmogorov–Smirnov) or confidence intervals yet; they need the incomplete gamma/beta functions and the Student's t distribution.
- Median and quantiles sort the whole array; a selection algorithm (quickselect) would make them O(n).
- Error causes are not distinguishable (
NANcovers invalid input and allocation failure). - Only
doubleis supported. - Planned: histograms and moving averages,
zscore, compensated summation, Python bindings.
include/cstats.h public API and documentation
src/cstats.c implementation
tests/test_main.c test runner
bench/bench.c micro-benchmark (optional target)
cmake/ warning flags helper
.github/workflows/ CI
Issues and pull requests are welcome. Please add a test with a reference value (ideally from Python's statistics) for any new function, and make sure the CI is green.
MIT. See LICENSE.
Andre Israel — @AndreIsraelAO