Functional Weave
Code in TypeScript

stats.standard-deviation@2.0.0

impl/typescript.ts

1,673 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { roundFloat } from "./math_round_float.ts";  ← from math.round-float ^1.0.0 · built alongside by fune
import { type DeviationKind } from "./stats_standard_deviation_types.ts";

/**
 * Population or sample standard deviation, two-pass.
 *
 * The one-pass "mean of squares minus square of mean" shortcut cancels
 * catastrophically on large, close values; two passes do not.
 */
export function standardDeviation(values: readonly number[], kind: DeviationKind, decimals: number): number {
  if (!Array.isArray(values)) throw new TypeError("values must be a list of numbers");
  for (const v of values) {
    if (typeof v !== "number" || !Number.isFinite(v)) {
      throw new TypeError(`values must be finite numbers, received ${v}`);
    }
  }
  if (kind !== "population" && kind !== "sample") {
    throw new RangeError(`unknown standard deviation kind "${kind}"`);
  }
  // Checked up front as well as in roundFloat (same wording), so a bad
  // decimals is reported before an empty list, as in 1.x.
  if (!Number.isInteger(decimals) || decimals < 0 || decimals > 12) {
    throw new RangeError(`decimals must be a whole number from 0 to 12, received ${decimals}`);
  }
  const n = values.length;
  if (n === 0) throw new RangeError("values must not be empty");
  if (kind === "sample" && n < 2) {
    throw new RangeError("sample standard deviation needs at least 2 values");
  }

  let sum = 0;
  for (const v of values) sum += v;
  const mean = sum / n;
  let squares = 0;
  for (const v of values) {
    const d = v - mean;
    squares += d * d;
  }
  // math.round-float rounds on the exact value of the double: 2.675 gives 2.67.
  return roundFloat(Math.sqrt(squares / (kind === "sample" ? n - 1 : n)), decimals);
}