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 🙏

© 2024 – Pkg Stats / Ryan Hefner

gmp-wasm

v1.1.0

Published

Arbitrary-precision Integer, Rational and Float types based on the GMP and MPFR libraries

Downloads

269

Readme

GMP-WASM

npm package codecov Build status JSDelivr downloads

Arbitrary-precision Integer, Rational and Float types based on the GMP and MPFR libraries.

Features

  • Supports all modern browsers, web workers, Node.js and Deno
  • Includes an easy-to-use, high-level wrapper, but low-level functions are also exposed
  • Has a lot more features, and in some cases, it's faster than the built-in BigInt type
  • The WASM binary is bundled as a compressed base64 string (no problems with linking)
  • Works even without Webpack or other bundlers
  • Includes TypeScript type definitions, check API here.
  • Zero dependencies
  • Full minified and gzipped bundle has a size of Bundle size
  • It also packages a mini bundle without Float/MPFR operations Bundle size
  • 100% open source & transparent build process

Installation

npm i gmp-wasm

It can also be used directly from HTML (via jsDelivr):

<!-- loads the full, minified library into the global `gmp` variable -->
<script src="https://cdn.jsdelivr.net/npm/gmp-wasm"></script>

<!-- or loads the non-minified library -->
<script src="https://cdn.jsdelivr.net/npm/gmp-wasm/dist/index.umd.js"></script>

<!-- or loads the minified library without Float/MPFR functions -->
<script src="https://cdn.jsdelivr.net/npm/gmp-wasm/dist/mini.umd.min.js"></script>

Usage

gmp-wasm also provides a high-level wrapper over the GMP functions. There are three major components:

  • g.Integer() - Wraps integers (MPZ)
  • g.Rational() - Wraps rational numbers (MPQ)
  • g.Float() - Wraps floating-point numbers (MPFR)
const gmp = require('gmp-wasm');

gmp.init().then(({ calculate }) => {
  // calculate() automatically deallocates all objects created within the callback function
  const result = calculate((g) => {
    const six = g.Float(1).add(5);
    return g.Pi().div(six).sin(); // sin(Pi/6) = 0.5
  });
  console.log(result);
});

It is also possible to delay deallocation through the getContext() API:

const gmp = require('gmp-wasm');

gmp.init().then(({ getContext }) => {
  const ctx = getContext();
  let x = ctx.Integer(1);
  for (let i = 2; i < 16; i++) {
    x = x.add(i);
  }
  console.log(x.toString());
  setTimeout(() => ctx.destroy(), 50);
});

The precision and the rounding modes can be set by passing a parameter to the context or to the Float constructor.

const roundingMode = gmp.FloatRoundingMode.ROUND_DOWN;
const options = { precisionBits: 10, roundingMode };

const result = calculate(g => g.Float(1).div(3), options);
// or
const result2 = calculate(g => g.Float(1, options).div(3));
// or
const ctx = getContext(options);
const result3 = ctx.Float(1).div(3).toString();

Predefined constants

  • Pi
  • EulerConstant
  • EulerNumber
  • Log2
  • Catalan

Advanced usage

High-level wrapper can be combined with low-level functions:

const sum = calculate((g) => {
  const a = g.Float(1);
  const b = g.Float(2);
  const c = g.Float(0);
  // c = a + b
  binding.mpfr_add(c.mpfr_t, a.mpfr_t, b.mpfr_t, 0);
  return c;
});

If you want more control and performance you can use the original GMP / MPFR functions even without high-level wrappers.

const gmp = require('gmp-wasm');

gmp.init().then(({ binding }) => {
  // Create first number and initialize it to 30
  const num1Ptr = binding.mpz_t();
  binding.mpz_init_set_si(num1Ptr, 30);
  // Create second number from string. The string needs to be copied into WASM memory
  const num2Ptr = binding.mpz_t();
  const strPtr = binding.malloc_cstr('40');
  binding.mpz_init_set_str(num2Ptr, strPtr, 10);
  // Calculate num1Ptr + num2Ptr, store the result in num1Ptr
  binding.mpz_add(num1Ptr, num1Ptr, num2Ptr);
  // Get result as integer
  console.log(binding.mpz_get_si(num1Ptr));
  // Deallocate memory
  binding.free(strPtr);
  binding.mpz_clears(num1Ptr, num2Ptr);
  binding.mpz_t_frees(num1Ptr, num2Ptr);
});

Sometimes, it's easier and faster to deallocate everything by reinitializing the WASM bindings:

// Deallocate all memory objects created by gmp-wasm
await binding.reset();

Performance

In some cases, this library can provide better performance than the built-in BigInt type.

For example, calculating 8000 digits of Pi using the following formula provides better results:

PI = 3
  + 3 * (1/2) * (1/3) * (1/4)
  + 3 * ((1 * 3)/(2 * 4)) * (1/5) * (1 / (4^2))
  + 3 * ((1 * 3 * 5) / (2 * 4 * 6)) * (1/7) * (1 / (4^3))
  + ...

| Test | Avg. time | Speedup | | ----------------------------------------------------------------------------------- | --------- | -------- | | With JS built-in BigInt type | 129 ms | 1x | | gmp-wasm Integer() high-level wrapper | 88 ms | 1.47x | | Same as previous with delayed memory deallocation | 78 ms | 1.65x | | gmp-wasm MPZ low-level functions | 53 ms | 2.43x | | decimal.js 10.3.1 with integer division | 443 ms | 0.29x | | big-integer 1.6.51 | 129 ms | 1x | | ---------------------------- | -------- | -------- | | gmp-wasm Float() high-level wrapper | 175 ms | 0.74x | | Same as previous with delayed memory deallocation | 169 ms | 0.76x | | gmp-wasm MPFR low-level functions | 118 ms | 1.09x | | decimal.js 10.3.1 with float division | 785 ms | 0.16x | | ---------------------------- | -------- | -------- | | gmp-wasm Float(1).atan().mul(4) | 0.6 ms | 215x | | gmp-wasm Float('0.5').asin().mul(6) | 17 ms | 7.59x |

* These measurements were made with Node.js v16.14 on an Intel Kaby Lake desktop CPU. Source code is here.