Subscribe to PHP Freaks RSS

bigint-money: an NPM package for doing currency math

syndicated from on January 23, 2019

Not long ago, I was confused about doing math with money and floating point issues. After a bunch of research and help from friends I figured out what many already did before me: Using floating points is indeed bad. You can get rounding issues and really want to use ‘precise math’.

After that, I realized I wanted to use the new Ecmascript bigint type as a basis for representing money. This is supported by recent versions of Node.js and Typescript, which is where I need it.

There’s a problem though, the bigint type only holds ‘whole numbers’ and doesn’t do fixed-point decimal-math. I looked around on NPM for something that would abstract this for me, but couldn’t find a library.

So I spent a couple of days writing a simple npm library called bigint-money that wraps the bigint type. It’s written in Typescript and open-source so it’s here for anyone to use:

Major features:


Most ‘money’ libraries on NPM only use 2 digits for precision, or use Javacript’s “number” and will quickly overflow.

The only comparible library I found was big-money. It’s probably the best alternative if your Javascript environment doesn’t have support for bigint yet.

My simple benchmark calculates a ledger with 1 million entries.

        bigint-money  |   big-money
ledger       816 ms   |   43.201 ms
%            100 %    |     5294 %

The benchmark script can be found in the repository.

I want to stress though that I can’t take credit for this (pretty good) result. The library is fast because bigint is fast.

I did need to implement a few functions myself, and I actually feel that somebody who’s better at writing fast code could probably do a much better job than I did.

I imagine that specifically the moneyValueToBigInt and bigintToFixed intenral functions could probably be optimized by someone much smarter than me.


This is how it generally works:

// Creating a money object.

import Money from 'bigint-money'; const foo = new Money('5', 'USD');

It’s possible to create a new money object with a Number as well

const foo = new Money(5, 'USD');

However, if you pass it a number that’s ‘unsafe’ such as a float, an error will be thrown:

const foo = new Money(.5, 'USD');
// Unsa

Truncated by Planet PHP, read more at the original (another 10860 bytes)