Skip to content

Instantly share code, notes, and snippets.

@guillermodlpa
Created May 29, 2024 07:28
Show Gist options
  • Save guillermodlpa/6e6ec45d698c4e33fa2c5e68d47ae60a to your computer and use it in GitHub Desktop.
Save guillermodlpa/6e6ec45d698c4e33fa2c5e68d47ae60a to your computer and use it in GitHub Desktop.
/**
* A set of utilities to operate with money amounts with decimals
*
* A piece of advice: don't use this! Instead, just work with integer values ALWAYS.
* Even doing the conversion to integer can cause issues (4.02 * 100 = 401.9999)
* So it's better to just always work with integers in a JavaScript/TypeScript codebase.
*
* Cheers
*/
const FACTORS_BY_NUM_DECIMALS = [10, 100, 1000] as const;
// we must operate with integers because of floating-point precision.
// E.g. 0.1 + 0.2 = 0.30000000000000004
export function addMoney(
n1: number,
n2: number,
{ decimalDigits = 2 }: { decimalDigits?: 1 | 2 | 3 } = {},
) {
const FACTOR = FACTORS_BY_NUM_DECIMALS[decimalDigits - 1];
return Math.round(FACTOR * n1 + FACTOR * n2) / FACTOR;
}
// we must operate with integers because of floating-point precision
// E.g. 10.1 * 3 = 30.299999999999997
// E.g. 4.02 * 100 = 401.99999999999994
export function multiplyMoney(
n1: number,
n2: number,
{ decimalDigits = 2 }: { decimalDigits?: 1 | 2 | 3 } = {},
) {
const FACTOR = FACTORS_BY_NUM_DECIMALS[decimalDigits - 1];
return roundDecimals(Math.round(FACTOR * n1 * (FACTOR * n2)) / (FACTOR * FACTOR));
}
// Necessary in some cases. E.g., 15.5 * 0.05 = 0.775
function roundDecimals(n: number, { numDecimals = 2 }: { numDecimals?: 1 | 2 | 3 } = {}): number {
const FACTOR = FACTORS_BY_NUM_DECIMALS[numDecimals - 1];
return Math.round(n * FACTOR) / FACTOR;
}
export function floatUnitsToCents(
amount: number,
{ decimalDigits = 2 }: { decimalDigits?: 1 | 2 | 3 } = {},
) {
const FACTOR = FACTORS_BY_NUM_DECIMALS[decimalDigits - 1];
return Math.round(amount * FACTOR);
}
export function getFloatUnitsToCents({ decimalDigits = 2 }: { decimalDigits?: 1 | 2 | 3 } = {}) {
return (amount: number) => floatUnitsToCents(amount, { decimalDigits });
}
export function centsToFloatUnits(
amount: number,
{ decimalDigits = 2 }: { decimalDigits?: 1 | 2 | 3 } = {},
) {
const FACTOR = FACTORS_BY_NUM_DECIMALS[decimalDigits - 1];
return amount / FACTOR;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment