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# (.NET 7+). 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.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
var (values, invalid) = Statistics.ParseNumbers("2, 4 4, 6, 8, 11, oops");
var s = Statistics.Summarize(values, sample: true); // population: sample: false
Console.WriteLine($"n={s.Count} sum={s.Sum} mean={s.Mean}");
Console.WriteLine($"median={s.Median} q1={s.Q1} q3={s.Q3} iqr={s.Iqr}");
Console.WriteLine($"min={s.Min} max={s.Max} range={s.Range}");
Console.WriteLine($"variance(sample)={s.Variance} stddev={s.StdDev}");
Console.WriteLine($"mode=[{string.Join(", ", s.Mode)}] invalid=[{string.Join(", ", invalid)}]");
public static class Statistics
{
public record ParseResult(List<double> Values, List<string> Invalid);
public record Stats(int Count, double Sum, double Mean, double Median, List<double> Mode,
double Min, double Max, double Range, double Variance, double StdDev,
double Q1, double Q3, double Iqr);
// Split on comma/whitespace runs; only fully-parsed finite tokens count as values.
public static ParseResult ParseNumbers(string input)
{
var values = new List<double>();
var invalid = new List<string>();
var seps = new[] { ' ', '\t', '\n', '\r' };
foreach (var tok in input.Replace(',', ' ').Split(seps, StringSplitOptions.RemoveEmptyEntries))
{
// NumberStyles.Float rejects trailing junk; inf/nan parse but fail the finite gate.
if (double.TryParse(tok, NumberStyles.Float, CultureInfo.InvariantCulture, out var v) && double.IsFinite(v))
values.Add(v);
else
invalid.Add(tok);
}
return new ParseResult(values, invalid);
}
// Linear-interpolation quantile (R-7 / NumPy / Excel PERCENTILE) over ascending, non-empty data.
static double Quantile(double[] s, double p)
{
double h = (s.Length - 1) * p;
int lo = (int)Math.Floor(h), hi = (int)Math.Ceiling(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 List<double> ComputeMode(double[] values)
{
var freq = new Dictionary<double, int>();
foreach (var v in values) freq[v] = freq.TryGetValue(v, out var c) ? c + 1 : 1;
if (freq.Count == 1) return new List<double> { values[0] }; // a single distinct value is the mode
int best = freq.Values.Max();
var modes = freq.Where(kv => kv.Value == best).Select(kv => kv.Key).OrderBy(v => v).ToList();
return modes.Count == freq.Count ? new List<double>() : modes;
}
public static Stats Summarize(IReadOnlyCollection<double> values, bool sample = true)
{
const double NaN = double.NaN;
if (values.Count == 0)
return new Stats(0, NaN, NaN, NaN, new List<double>(), NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN);
var s = values.OrderBy(v => v).ToArray();
double sum = 0;
foreach (var v in values) sum += v; // sum in original order
double mean = sum / values.Count, ss = 0;
foreach (var v in values) ss += (v - mean) * (v - mean);
// Sample variance needs n >= 2; the population estimator always divides by n.
double variance = sample ? (values.Count >= 2 ? ss / (values.Count - 1) : NaN) : ss / values.Count;
double q1 = Quantile(s, 0.25), med = Quantile(s, 0.5), q3 = Quantile(s, 0.75);
return new Stats(values.Count, sum, mean, med, ComputeMode(s), s[0], s[^1], s[^1] - s[0],
variance, Math.Sqrt(variance), q1, q3, q3 - q1);
}
}
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 →