allocate
Distributes an amount proportionally according to given ratios. Handles rounding to ensure the sum equals the original amount exactly. Critical for financial operations like splitting payments to avoid rounding errors.
Implementation
View Source Code
ts
/**
* Distributes an amount proportionally according to given ratios.
* Handles rounding to ensure the sum equals the original amount exactly.
* Critical for financial operations like splitting payments to avoid rounding errors.
*
* @example
* ```ts
* // Split $100 in ratio 1:2:3
* allocate(100, [1, 2, 3]);
* // [17, 33, 50] - sum is exactly 100
*
* // Split with bigint (e.g., cents)
* allocate(10000n, [1, 1, 1]);
* // [3334n, 3333n, 3333n] - sum is exactly 10000n
* ```
*
* @param amount - Total amount to allocate
* @param ratios - Array of ratios for distribution
* @returns Array of allocated amounts (sum equals original amount)
* @throws {Error} If ratios array is empty or contains negative values
*/
export function allocate(amount: number, ratios: number[]): number[];
export function allocate(amount: bigint, ratios: number[]): bigint[];
export function allocate(amount: number | bigint, ratios: number[]): (number | bigint)[] {
if (ratios.length === 0) {
throw new Error('Ratios array cannot be empty');
}
if (ratios.some((r) => r < 0)) {
throw new Error('Ratios must be non-negative');
}
const totalRatio = ratios.reduce((sum, ratio) => sum + ratio, 0);
if (totalRatio === 0) {
throw new Error('Total ratio cannot be zero');
}
if (typeof amount === 'bigint') {
const results: bigint[] = [];
let remainder = amount;
for (let i = 0; i < ratios.length - 1; i++) {
const share = (amount * BigInt(Math.floor(ratios[i] * 1000000))) / BigInt(Math.floor(totalRatio * 1000000));
results.push(share);
remainder -= share;
}
// Last allocation gets the remainder to ensure exact sum
results.push(remainder);
return results;
}
// Handle number type
const results: number[] = [];
let remainder = amount;
for (let i = 0; i < ratios.length - 1; i++) {
const share = Math.floor((amount * ratios[i]) / totalRatio);
results.push(share);
remainder -= share;
}
// Last allocation gets the remainder to ensure exact sum
results.push(remainder);
return results;
}Features
- Proportional Distribution: Split amounts according to custom ratios
- No Rounding Errors: Sum always equals original amount exactly
- Precision: Works with bigint for financial calculations
- Type-Safe: Separate overloads for number and bigint
- Error Handling: Validates ratios and prevents invalid operations
- Isomorphic: Works in both Browser and Node.js
API
ts
function allocate(amount: number, ratios: number[]): number[];
function allocate(amount: bigint, ratios: number[]): bigint[];Parameters
amount: Total amount to allocate (number or bigint)ratios: Array of ratios for distribution (e.g.,[1, 2, 3])
Returns
- Array of allocated amounts (sum equals original amount)
Throws
Error: If ratios array is emptyError: If ratios contain negative valuesError: If total ratio is zero
Examples
Basic Proportional Allocation
ts
import { allocate } from '@vielzeug/toolkit';
// Split $100 in ratio 1:2:3
allocate(100, [1, 2, 3]);
// [16, 33, 51] - sum is exactly 100Split by Percentage
ts
import { allocate } from '@vielzeug/toolkit';
// Split revenue: 50% partner A, 30% partner B, 20% partner C
const revenue = 100000n; // $1,000.00
allocate(revenue, [50, 30, 20]);
// [50000n, 30000n, 20000n]Real-World Example: Payment Commission
ts
import { allocate } from '@vielzeug/toolkit';
const saleAmount = 500000n; // $5,000.00
// Split: 70% to company, 20% to salesperson, 10% to referrer
const [company, salesperson, referrer] = allocate(saleAmount, [70, 20, 10]);
// company: 350000n ($3,500.00)
// salesperson: 100000n ($1,000.00)
// referrer: 50000n ($500.00)Investment Portfolio Distribution
ts
import { allocate } from '@vielzeug/toolkit';
const totalInvestment = 1000000n; // $10,000.00
// Portfolio: 60% stocks, 30% bonds, 10% cash
const [stocks, bonds, cash] = allocate(totalInvestment, [60, 30, 10]);
// stocks: 600000n ($6,000.00)
// bonds: 300000n ($3,000.00)
// cash: 100000n ($1,000.00)Handling Remainders Correctly
ts
import { allocate } from '@vielzeug/toolkit';
// Split $100 equally among 3 parties
allocate(100, [1, 1, 1]);
// [34, 33, 33] - sum is exactly 100 (no penny lost!)
// With bigint (cents)
allocate(10000n, [1, 1, 1]);
// [3334n, 3333n, 3333n] - sum is exactly 10000nTax Distribution
ts
import { allocate } from '@vielzeug/toolkit';
const totalTax = 150000n; // $1,500.00 total tax collected
// Federal: 60%, State: 30%, Local: 10%
const [federal, state, local] = allocate(totalTax, [60, 30, 10]);
// federal: 90000n ($900.00)
// state: 45000n ($450.00)
// local: 15000n ($150.00)Unequal Ratios
ts
import { allocate } from '@vielzeug/toolkit';
// Split bonus: Senior gets 5 shares, Junior gets 3 shares
const bonus = 800000n; // $8,000.00
const [senior, junior] = allocate(bonus, [5, 3]);
// senior: 500000n ($5,000.00)
// junior: 300000n ($3,000.00)Implementation Notes
- Remainder Handling: The last allocation gets any remainder to ensure exact sum
- Ratio Type: Ratios can be any positive numbers (integers or decimals)
- Zero Ratios: Ratios of zero are allowed (will receive zero allocation)
- Precision: Uses bigint arithmetic for financial precision when needed
- Order: Results are in the same order as the ratio array
- Rounding: Uses floor rounding, with remainder going to last item
- Use Case: Perfect for splitting payments, commissions, taxes, or any proportional distribution
See Also
- distribute: Distribute amount evenly among N parties
- divide: Simple division
- multiply: Multiply numbers