npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dezimal

v0.1.0

Published

A lightweight arbitrary-precision Decimal library

Readme

dezimal

Arbitrary-precision decimal arithmetic for JavaScript and TypeScript: a sub-1 kB core and an opt-in extension for every operation.

dezimal is German for decimal.

[!WARNING] dezimal is an experiment: it explores how much smaller and more modern a decimal library can be than decimal.js. Almost all of its code was written with AI. It is tested extensively, including against decimal.js, but correctness is not guaranteed — verify results before relying on them for anything critical.

import { Decimal } from "dezimal";
import "dezimal/preset/basic";

new Decimal("0.1").plus("0.2").toString(); // "0.3"
  • Pay for what you use. The core only parses and stores values (0.9 kB min+gzip). Operations are extensions you import individually or as presets; everything together is about 5 kB.
  • Types follow your imports. Importing an extension adds its methods to the Decimal type, so calling something you did not import is a compile error, not a runtime surprise.
  • Exact where possible. Addition, subtraction, multiplication and rounding to a scale are exact (bigint based) and never lose digits. Only operations that cannot be exact, such as division, roots and logarithms, round to a configurable precision, and those results are correctly rounded.
  • No NaN, no Infinity, no -0. Every value is a finite decimal. Invalid operations throw instead of producing special values.
  • Fast. On typical inputs most operations run 1.5–5× faster than decimal.js (see Size and performance).

Install

npm install dezimal

dezimal ships as ES modules and relies on bigint (ES2020).

Usage

Import the core once and the extensions you need as side-effect imports, usually in your entry file:

import { Decimal } from "dezimal";
import "dezimal/preset/basic"; // arithmetic, compare, max/min/sum, toString
import "dezimal/ops/sqrt"; // single extensions work too

const price = new Decimal("19.99");
const total = price.times(3).plus("4.95");

total.toString(); // "64.92"
total.sqrt({ precision: 8 }).toString(); // "8.0572948"

Values are immutable; every operation returns a new Decimal. Every argument accepts a DecimalLike: a Decimal, a string, a number, a bigint, or a raw [coefficient, exponent] tuple.

new Decimal("1.50"); // 1.5 — values are normalized
new Decimal("-1.2e-5");
new Decimal(0.1); // 0.1 — numbers are read via their shortest string form
new Decimal(123n);
new Decimal([12345n, -2]); // 123.45

Presets

| Import | Contents | | --- | --- | | dezimal/preset/basic | plus, minus, times, divide, divideInteger, modulo, absolute, negate, compare, sign, max, min, sum, toString, toPlainString | | dezimal/preset/predicate | equals, greaterThan, greaterThanOrEqual, lessThan, lessThanOrEqual, isZero, isInteger, isNegative, isPositive, compare, sign | | dezimal/preset/rounding | round, floor, ceil, truncate, toDecimalPlaces, toSignificantDigits, toNearest, clamp, toFixed, decimalPlaces, significantDigits | | dezimal/preset/power | sqrt, cbrt, pow, exp, ln, log (+ Decimal.log2, Decimal.log10), Decimal.hypot | | dezimal/preset/format | toString, toPlainString, toFixed, toExponential, toPrecision, toNumber, decimalPlaces, significantDigits | | dezimal/preset/config | Decimal.precision, Decimal.rounding, Decimal.ln10 | | dezimal/preset/full | everything |

Every extension is also available on its own as dezimal/<kind>/<name>, for example dezimal/ops/divide, dezimal/check/is-zero or dezimal/format/to-fixed:

| Kind | Extensions | | --- | --- | | dezimal/ops/* | plus, minus, times, divide, divide-integer, modulo, absolute, negate, sum, max, min, round, floor, ceil, truncate, to-decimal-places, to-significant-digits, to-nearest, clamp, sqrt, cbrt, pow, exp, ln, log, hypot | | dezimal/check/* | compare, equals, greater-than, greater-than-or-equal, less-than, less-than-or-equal, sign, is-zero, is-integer, is-negative, is-positive, is-decimal, decimal-places, significant-digits | | dezimal/format/* | to-string, to-plain-string, to-fixed, to-exponential, to-precision, to-number, to-big-int, to-json | | dezimal/config/* | precision, rounding-modes, ln10 |

Extensions register themselves on import and pull in what they depend on. Importing the same extension from several places is harmless.

Many operations have short aliases: add, sub, mul, div, mod, abs, eq, gt, gte, lt, lte, toDP, toSD, and more.

Precision and rounding

The arithmetic family (plus, minus, times, modulo, sum, …) and the quantization family (round, toDecimalPlaces, toNearest, …) are exact: they keep every digit or round to the scale you ask for.

Operations whose results generally have infinitely many digits (divide, divideInteger, sqrt, cbrt, pow, exp, ln, log, hypot) round to Decimal.precision significant digits (default 20) using Decimal.rounding (default "half-up"):

new Decimal(1).divide(3).toString(); // "0.33333333333333333333"

Decimal.precision = 10;
Decimal.rounding = "half-even";
new Decimal(2).divide(3).toString(); // "0.6666666667"

Each of these operations also takes per-call options. This lets library code stay independent of the global configuration:

new Decimal(1).divide(3, { precision: 5 }).toString(); // "0.33333"
new Decimal(2).sqrt({ precision: 50, rounding: "down" });
new Decimal(2).log(10, { precision: 5 }); // log10(2) → 0.30103

Results are correctly rounded: computed with guard digits and rounded once, and exactly representable results stay exact (Decimal.log2(8) is 3, and new Decimal(4).pow("0.5") is 2).

Rounding modes:

| Mode | Rounds towards | | --- | --- | | "up" / "down" | away from zero / towards zero | | "ceil" / "floor" | +∞ / −∞ | | "half-up" / "half-down" | nearest; ties away from / towards zero | | "half-even" | nearest; ties to the even neighbour (banker's rounding) | | "half-ceil" / "half-floor" | nearest; ties towards +∞ / −∞ |

Quantization and formatting methods take an explicit mode as well:

new Decimal("0.125").toDecimalPlaces(2).toString(); // "0.13"
new Decimal("0.125").toDecimalPlaces(2, "half-even").toString(); // "0.12"
new Decimal("19.999").toFixed(2); // "20.00"

Values and errors

  • Finite only. "NaN", "Infinity" and malformed input throw a TypeError or RangeError at construction. Division by zero, sqrt of a negative value, ln of a non-positive value and similar operations throw a RangeError.
  • Bounded exponent. Values and results must stay within ±Decimal.exponentLimit (999 999) in exponent. Leaving that range throws a RangeError in both directions: very small results do not silently become zero.
  • Normalized. Trailing zeros are dropped ("1.50" is stored as 1.5) and zero is always plain 0.
  • No implicit number coercion. Template literals and String(value) use toString(), but a < b, a + b and +a throw a TypeError instead of silently comparing or concatenating strings. Use compare/lessThan/plus and toNumber() instead.
  • JSON. With dezimal/format/to-json, JSON.stringify writes values as lossless strings. Read them back with new Decimal(string).
JSON.stringify({ price: new Decimal("19.99") }); // '{"price":"19.99"}'
new Decimal("1.5e3").toBigInt(); // 1500n

Coming from decimal.js

dezimal covers the commonly used decimal.js API with a few deliberate differences:

  • Operations are opt-in imports instead of all built in.
  • plus, minus, times, modulo and sum are exact instead of rounded to precision.
  • There are no NaN, ±Infinity or -0 values, so no isNaN/isFinite. Invalid operations throw, and so do results beyond the exponent range in either direction.
  • Names are verbs with short aliases: divide/div instead of dividedBy, and lessThanOrEqual/lte instead of lessThanOrEqualTo.
  • Rounding modes are strings ("half-even") instead of numeric constants.
  • Precision-based operations accept per-call { precision, rounding } options instead of requiring Decimal.clone().

Not yet available: trigonometric and hyperbolic functions, base-2/8/16 conversion, toFraction and random. See ROADMAP.md.

Size and performance

Bundle size (min+gzip, including the core):

| Import | Size | | --- | --- | | core only | 0.9 kB | | preset/basic | 2.5 kB | | preset/full | 5.0 kB |

Throughput relative to decimal.js 10.6 on Node 26 (higher is better), measured with pnpm run bench:

| Operation | typical operands, precision 20 | 50-digit operands, precision 50 | | --- | --- | --- | | parse | 1.5× | | | plus / minus | 2.5× / 2.2× | 1.1× / – | | times | 3.4× | 9.6× | | divide | 1.7× | 3.6× | | compare / toString / toFixed | 1.3× / 1.0× / 1.2× | | | sqrt | 5.2× | 8.3× | | exp / ln | 4.6× / 2.0× | – / 2.8× | | pow (fractional / integer) | 2.3× / 1.1× | |

License

MIT