/** * Exact money arithmetic helpers — `mulRate` and `allocate`. * * Both operate on the canonical decoded string form that `get()` * returns (`'10000.00'`), entirely in scaled-`BigInt` space — no * floating-point step anywhere, exact past 2^53. They are pure * functions with no vault or descriptor dependency: the working scale * is inferred from the amount's fractional digits (a canonical money * string always carries exactly the field's scale) or pinned with * `opts.scale`. * * Why these two: app-side invariants of the form * `Σ parts === whole` (receipt totals, net-zero WHT pairs, proration) * carry ±0.01 tolerances ONLY because the math is major-unit floats + * round2. `mulRate` (VAT-style rate application with explicit * rounding) and `allocate` (largest-remainder split — parts sum to the * input EXACTLY, by construction) make those tolerances zero. */ import { type RoundingMode } from './fixed-point.js'; export interface MulRateOptions { /** * Output scale (fraction digits). Defaults to the amount's own * fractional digits — for a canonical money string that IS the * field's scale. */ readonly scale?: number; /** Rounding for the final re-scale. Default `'half-up'`. */ readonly rounding?: RoundingMode; } export interface AllocateOptions { /** Working scale. Defaults to the amount's own fractional digits. */ readonly scale?: number; } /** * Multiply a money amount by a decimal rate, exactly. * * The rate is parsed at its OWN full precision (`0.07` → `7` at scale * 2), the product computed in `BigInt` at `amountScale + rateScale`, * then re-scaled back to the output scale with the requested rounding — * one rounding step, at the very end. * * ```ts * mulRate('10000.00', 0.07) // '700.00' (VAT) * mulRate('33.33', '0.07') // '2.33' (half-up) * mulRate('33.33', 0.07, { rounding: 'floor' }) // '2.33' * mulRate(100, 0.07, { scale: 2 }) // '7.00' * ``` */ export declare function mulRate(amount: number | string, rate: number | string, opts?: MulRateOptions): string; /** * Split a money amount across weighted buckets with ZERO drift: the * returned parts sum to the input exactly, by construction * (largest-remainder method). * * Each bucket gets `floor(amount × weightᵢ / Σweights)`; the leftover * minor units (always fewer than the bucket count) go one each to the * buckets with the largest truncated remainders — ties broken by * position, earlier bucket first. Weights are parsed as exact decimals * (no float division anywhere); they must be non-negative with a * positive sum. * * ```ts * allocate('100.00', [1, 1, 1]) // ['33.34', '33.33', '33.33'] * allocate('0.05', [3, 7]) // ['0.02', '0.03'] * allocate('-100.00', [1, 1, 1]) // ['-33.34', '-33.33', '-33.33'] * ``` */ export declare function allocate(amount: number | string, weights: ReadonlyArray, opts?: AllocateOptions): string[];