Statistics Calculator — Ruby 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 Ruby implementation — the same logic the interactive tool runs, in a shareable, citable form.
# statistics — descriptive statistics over a free-form number list. Language: Ruby (3.1+, stdlib only). 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.
# Split on comma/whitespace runs; only fully-parsed finite tokens count as values.
def parse_numbers(input)
values = []
invalid = []
input.gsub(',', ' ').split.each do |tok|
v = Float(tok, exception: false) # accepts inf/nan — filtered by finite?
v&.finite? ? values << v : invalid << tok
end
[values, invalid]
end
# Linear-interpolation quantile (R-7 / NumPy / Excel PERCENTILE) over ascending, non-empty data.
def quantile(sorted, p)
h = (sorted.length - 1) * p
lo = h.floor
hi = h.ceil
lo == hi ? sorted[lo] : sorted[lo] + (h - lo) * (sorted[hi] - sorted[lo])
end
# Most frequent value(s), ascending; empty when every distinct value ties (uniform).
def compute_mode(values)
freq = values.tally
return [values[0]] if freq.size == 1 # a single distinct value is the mode
best = freq.values.max
modes = freq.select { |_, c| c == best }.keys.sort
modes.size == freq.size ? [] : modes
end
def summarize(values, sample: true)
n = values.length
nan = Float::NAN
return { count: 0, sum: nan, mean: nan, median: nan, mode: [], min: nan, max: nan,
range: nan, variance: nan, stddev: nan, q1: nan, q3: nan, iqr: nan } if n.zero?
sorted = values.sort
sum = values.sum # sum in original order
mean = sum / n
ss = values.sum { |x| (x - mean)**2 }
# Sample variance needs n >= 2; the population estimator always divides by n.
variance = sample ? (n >= 2 ? ss / (n - 1) : nan) : ss / n
q1 = quantile(sorted, 0.25)
med = quantile(sorted, 0.5)
q3 = quantile(sorted, 0.75)
{ count: n, sum:, mean:, median: med, mode: compute_mode(values), min: sorted[0], max: sorted[-1],
range: sorted[-1] - sorted[0], variance:, stddev: Math.sqrt(variance), q1:, q3:, iqr: q3 - q1 }
end
values, invalid = parse_numbers('2, 4 4, 6, 8, 11, oops')
s = summarize(values) # sample=true — population: summarize(values, sample: false)
puts "n=#{s[:count]} sum=#{s[:sum]} mean=#{s[:mean]}"
puts "median=#{s[:median]} q1=#{s[:q1]} q3=#{s[:q3]} iqr=#{s[:iqr]}"
puts "min=#{s[:min]} max=#{s[:max]} range=#{s[:range]}"
puts "variance(sample)=#{s[:variance]} stddev=#{s[:stddev]}"
puts "mode=#{s[:mode]} invalid=#{invalid}"
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 →