Skip to content

Repository files navigation

decimation

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))

Motivation

JavaScript decimal libraries require hard to follow method chaining. For example:

functioncompoundInterest(principal,rate,n,t){returnprincipal.mul(newDecimal(1).add(newDecimal(rate).div(n)).pow(newDecimal(n).mul(t)))}

Same example in decimation:

functioncompoundInterest(principal,rate,n,t){returnmath`${principal} * (1 + ${rate} / ${n}) ** (${n} * ${t})`}

Decimal requires methods like .gt() to compare, and sum() is not ergonomic:

constisOver=Decimal.sum(0, ...items).mul(newDecimal(1).add(taxRate)).gt(budget)

Same example in decimation:

constisOver=is`sum(${items}) * (1 + ${taxRate}) > ${budget}`

Install

npm install decimation

Import

For 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)

Usage

// Same as a.add(b.mul(c))consttotal=math`${a} + ${b} * ${c}`// Same as a.add(b.mul(2)).gt(c.sub(20))if(is`${a} + ${b} * 2 > ${c} - 20`){ ... }

Features

  • 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: math returns Decimal; is returns boolean.
  • Low overhead: Templates are parsed once into an Abstract Syntax Tree and cached to WeakMap. Even inside loops:
    constsubtotals=items.map(item=>// parsed only once, because string literal does not changemath`sum(${item.prices}) * (1 + ${tax})`.toDecimalPlaces(2))

Reference

Tagged templates:

  • math evaluates an expression and returns a Decimal.
  • is evaluates 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'importMyDecimalfrom'./my-decimal.js'const{ math, is }=create(MyDecimal)

Operators available within templates, from highest to lowest precedence:

OperatorAssociativity
**Right
*, /Left
+, -Left
==, !=, <, >, <=, >=Left

Functions available within templates:

  • abs(x): absolute value
  • ceil(x): round up to the nearest integer
  • floor(x): round down to the nearest integer
  • round(x): round to the nearest integer
  • clamp(x, min, max): restrict x between min and max
  • sum(array): sum of all elements in array

Development

npm install
# test and lint
npm test
npm run typecheck
npm run lint
npm run format:check
# publish
npm publish

About

Natural math notation library for JavaScript decimals

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages