QuickJS already supports arbitrary-precision decimals
QuickJS is a neat JavaScript engine by Fabrice Bellard. It’s fast and small (version 2021-03-27 clocks in at 759 Kb). It includes support for arbitrary-precision decimals, even though the TC39 decimal proposal is (at the time of writing) still at Stage 2. You can install it using the tool of your choice; I was able to install it using Homebrew for macOS (the formula is called quickjs
) and FreeBSD and OpenBSD. It can also be installed using esvu. (It doesn’t seem to be available as a package on Ubuntu.) To get started with arbitrary precision decimals, you need to fire up QuickJS with the bignum
flag:
$ qjs --bignum
QuickJS - Type "\h" for help
qjs > 0.1 + 0.2 === 0.3
false
qjs > 0.1m + 0.2m === 0.3m
true
qjs > 0.12345678910111213141516171819m * 0.19181716151413121110987654321m
0.0236811308550240594910066199325923006903586430678413779899m
(The m
is the proposed suffix for literal high-precision decimal numbers that proposal-decimal is supposed to give us.) Notice how we nicely unbreak JavaScript decimal arithmetic, without having to load a library. The final API in the official TC39 Decimal proposal still has not been worked out. Indeed, a core question there remains outstanding at the time of writing: what kind of numeric precision should be supported? (The two main contenders are arbitrary precision and the other being 128-bit IEEE 754 (high, but not *arbitrary*, precision). QuickJS does arbitrary precision.) Nonetheless, QuickJS provides a BigDecimal
function:
qjs > BigDecimal("123456789.0123456789")
123456789.0123456789m
Moreover, you can do basic arithmetic with decimals: addition, subtraction, multiplication, division, modulo, square roots, and rounding. Everything is done with infinite precision (no loss of information). If you know, in advance, what precision is needed, you can tweak the arithmetical operations by passing in an options argument. Here’s an example of adding two big decimal numbers:
qjs > var a = 0.12345678910111213141516171819m;
undefined
qjs > var b = 0.19181716151413121110987654321m;
undefined
qjs > BigDecimal.add(a,b)
0.3152739506152433425250382614m
qjs > BigDecimal.add(a,b, { "roundingMode": "up", "maximumFractionDigits": 10 })
0.3152739507m
Jesse Alama