Functional Weave
Code in TypeScript

math.round-div@1.0.0

impl/typescript.ts

1,423 bytes · the TypeScript implementation · view raw

import { type RoundingMode } from "./math_round_div_types.ts";

/**
 * Divide two integers, rounding according to `mode`.
 *
 * Money is held in minor units (pence, cents) as integers. Every rate,
 * discount and tax calculation eventually needs to divide, and that division
 * is where rounding policy lives. Making it explicit here means a system can
 * state its policy once instead of scattering `Math.round` through a codebase.
 */
export function roundDiv(numerator: number, denominator: number, mode: RoundingMode = "half-up"): number {
  if (!Number.isInteger(numerator) || !Number.isInteger(denominator)) {
    throw new TypeError("roundDiv operates on integers only");
  }
  if (denominator === 0) {
    throw new RangeError("denominator must not be zero");
  }

  const negative = numerator < 0 !== denominator < 0;
  const n = Math.abs(numerator);
  const d = Math.abs(denominator);

  let quotient = Math.floor(n / d);
  const remainder = n - quotient * d;
  const twice = remainder * 2;

  switch (mode) {
    case "down":
      break;
    case "up":
      if (remainder > 0) quotient += 1;
      break;
    case "half-even":
      if (twice > d || (twice === d && quotient % 2 === 1)) quotient += 1;
      break;
    case "half-up":
      if (twice >= d) quotient += 1;
      break;
    default:
      throw new RangeError(`unknown rounding mode "${mode}"`);
  }

  return negative ? -quotient : quotient;
}