Natural math notation library for JavaScript decimals, using tagged templates:
import { math } from 'decimation/decimal.js'
math`${a} + ${b} * 2` // a.add(b.mul(2))JavaScript decimal libraries require hard to follow method chaining. For example:
function compoundInterest(principal, rate, n, t) {
return principal.mul(
new Decimal(1).add(
new Decimal(rate).div(n)
).pow(
new Decimal(n).mul(t)
)
)
}Same example in decimation:
function compoundInterest(principal, rate, n, t) {
return math`${principal} * (1 + ${rate} / ${n}) ** (${n} * ${t})`
}Decimal requires methods like .gt() to compare, and sum() is not ergonomic:
const isOver = Decimal.sum(0, ...items)
.mul(new Decimal(1).add(taxRate))
.gt(budget)Same example in decimation:
const isOver = is`sum(${items}) * (1 + ${taxRate}) > ${budget}`npm install decimationFor decimal.js:
import { is, math } from 'decimation/decimal.js'For Prisma Decimal:
import { is, math } from 'decimation/prisma'For a custom library:
import { create } from 'decimation'
import { MyDecimal } from './my-decimal.js'
const { math, is } = create(MyDecimal)// Same as a.add(b.mul(c))
const total = math`${a} + ${b} * ${c}`
// Same as a.add(b.mul(2)).gt(c.sub(20))
if (is`${a} + ${b} * 2 > ${c} - 20`) { ... }- Operator overload: Standard math operators mapping to Decimal methods. E.g.,
+to.add(),*to.mul(). - Automatic casting: Literals, strings and numbers are automatically cast to the
Decimal. - Type safety:
mathreturnsDecimal;isreturnsboolean. - Low overhead: Templates are parsed once into an Abstract Syntax Tree and cached to
WeakMap. Even inside loops:const subtotals = items.map(item => // parsed only once, because string literal does not change math`sum(${item.prices}) * (1 + ${tax})`.toDecimalPlaces(2) )
mathevaluates an expression and returns aDecimal.isevaluates an expression and returns a boolean. Requires top-level comparison operator.
Function:
create(D)returns{ math, is }bound to any Decimal.js-compatible constructor. For example:import { create } from 'decimation' import MyDecimal from './my-decimal.js' const { math, is } = create(MyDecimal)
Operators available within templates, from highest to lowest precedence:
| Operator | Associativity |
|---|---|
** |
Right |
*, / |
Left |
+, - |
Left |
==, !=, <, >, <=, >= |
Left |
Functions available within templates:
abs(x): absolute valueceil(x): round up to the nearest integerfloor(x): round down to the nearest integerround(x): round to the nearest integerclamp(x, min, max): restrictxbetweenminandmaxsum(array): sum of all elements inarray
npm install
# test and lint
npm test
npm run typecheck
npm run lint
npm run format:check
# publish
npm publish