1.1.0 • Published 4 years ago

bigint-lib v1.1.0

Weekly downloads
3
License
MIT
Repository
github
Last release
4 years ago

Build Status codecov HitCount dependencies

bigint-lib

Use BigInt in library code, whether native or polyfilled.


Installation

npm install --save bigint-lib

Usage

If polyfilling, polyfill BigInt first.

Then,

import {bigIntLib} from "bigint-lib";

/**
 * `true` if natively supported; `false` otherwise
 */
bigIntLib.isNativelySupported();

/**
 * `true` if considered a `BigInt`
 */
bigIntLib.isBigInt(x);

/**
 * Creates a `BigInt` instance
 */
bigIntLib.BigInt(0);

See API for more details

Since this library is meant for library authors, reading the source code to understand how it works internally is recommended.


Motivation

Not all browsers support BigInt natively.

https://caniuse.com/#feat=mdn-javascript_builtins_bigint


Application code can use polyfills for BigInt easily.

https://github.com/GoogleChromeLabs/jsbi


However, libraries cannot assume that BigInt is natively supported, or polyfilled.

A library has to check.

If it is natively supported, we can use BigInt and all built-in operations directly.

If it is polyfilled, we cannot assume the shape of the exposed API for built-in operations.

Is addition done with x.add(y)? Or Polyfill.add(x, y)? Or x.plus(y)? Is it even implemented at all?

What about every other operation?


This library provides a unified API for all built-in BigInt operations, regardless of whether BigInt is natively supported, or polyfilled.


How it works

This library's only dependency is jsbi.

We have three cases to handle,

  • BigInt is natively supported

    We use the built-in operations directly.

    This is the most efficient.

    See src/native.ts for more details.

  • BigInt is polyfilled using jsbi

    We use jsbi for built-in operations.

    This is still pretty efficient.

    See src/jsbi-polyfill.ts for more details.

  • BigInt is polyfilled using some other library

    We convert the other library's BigInt to JSBI, use jsbi for built-in operations, and convert the result back to the other libary's BigInt.

    This is the least efficient, but saves us from having to worry about the exposed API of the other library.

    See src/non-jsbi-polyfill.ts for more details.


Expected Polyfill

This library assumes polyfills conform to some minimal API.


Polyfill with JSBI

To polyfill using jsbi,

import JSBI from "jsbi";
global.BigInt = JSBI.BigInt;

At the moment, using jsbi+TypeScript with esModuleInterop:false may cause the import to fail during run-time.

You may set esModuleInterop:true to fix the problem. However, setting esModuleInterop:true may cause other imports to fail.

You may choose to keep esModuleInterop:false and change the import to,

import {JSBI} from "bigint-lib/dist/jsbi";
global.BigInt = JSBI.BigInt;

Polyfill with Other Library

If polyfilling with some other library, the library must, minimally, have the following API,

class MyPolyfill {
    constructor (mixed : any) {
        //snip https://tc39.es/ecma262/#sec-bigint-constructor
    }

    toString () {
        return //snip base-10 string
    }
}
global.BigInt = (mixed : any) => new MyPolyfill(mixed);

The polyfill must also satisfy the following properties,

BigInt(0) instanceof MyPolyfill
> true
Object.getPrototypeOf(BigInt(0)).constructor === MyPolyfill
> true

API

The following are exported by this library,


BigIntLib

The interface is mostly the same as jsbi's

Operationnative BigIntbigint-libNote
Creation from Stringa = BigInt("456")a = biLib.BigInt("456")
Creation from Numbera = BigInt(789)a = biLib.BigInt(789)
Creation from BigInta = BigInt(a)a = biLib.BigInt(a)
Conversion to Stringa.toString(radix)biLib.toString(a, radix)radix defaults to 10; must be in 2, 36
Conversion to NumberNumber(a)biLib.toNumber(a)May result in precision loss
TruncationBigInt.asIntN(width, a)biLib.asIntN(width, a)Throws if width is negative
BigInt.asUintN(width, a)biLib.asUintN(width, a)Throws if width is negative
Type checktypeof a === "bigint"biLib.isBigInt(a)
Native BigInt checktypeof BigInt(0) === "bigint"biLib.isNativelySupported()

Operationnative BigIntbigint-libNote
Arithmetic
Unary minusb = -ab = biLib.unaryMinus(a)
Additionc = a + bc = biLib.add(a, b)
Subtractionc = a - bc = biLib.subtract(a, b)
Multiplicationc = a * bc = biLib.multiply(a, b)
Divisionc = a / bc = biLib.divide(a, b)Throws if b is zero
Remainderc = a % bc = biLib.remainder(a, b)Throws if b is zero
Exponentiationc = a ** bc = biLib.exponentiate(a, b)Throws if b is negative
Bitwise
Left-shiftc = a << bc = biLib.leftShift(a, b)Allows negative shift
Signed right-shiftc = a >> bc = biLib.signedRightShift(a, b)Allows negative shift
Bitwise NOTb = ~ac = biLib.bitwiseNot(a)
Bitwise ANDc = a & bc = biLib.bitwiseAnd(a, b)
Bitwise ORc = a \| bc = biLib.bitwiseOr(a, b)
Bitwise XORc = a ^ bc = biLib.bitwiseXor(a, b)
Comparisona == bbiLib.equal(a, b)
a != bbiLib.notEqual(a, b)
a < bbiLib.lessThan(a, b)
a <= bbiLib.lessThanOrEqual(a, b)
a > bbiLib.greaterThan(a, b)
a >= bbiLib.greaterThanOrEqual(a, b)
Unsupported
Literalsa = 123nN/A
Incrementa++/++aN/A
a + 1nbiLib.add(a, biLib.BigInt(1))
Decrementa--/--aN/A
a - 1nbiLib.subtract(a, biLib.BigInt(1))

nativeOrJsbiLib

If global.BigInt is natively supported, returns nativeBigIntLib. Otherwise, returns jsbiPolyfillBigIntLib.

This is useful for libraries that need to perform many complex BigInt operations before returning a result.


import {bigIntLib, nativeOrJsbiLib} from "bigint-lib";

const my1 = nativeOrJsbiLib.BigInt(1);

//Takes native or JSBI polyfilled bigints
//Will return a native or JSBI polyfilled bigint
function myComplexFunctionImpl (m : bigint, n : bigint) : bigint {
    if (nativeOrJsbiLib.equal(m, 0)) {
        return nativeOrJsbiLib.add(n, my1);
    }
    if (nativeOrJsbiLib.equal(n, 0)) {
        return myComplexFunctionImpl(
            nativeOrJsbiLib.subtract(m, my1),
            my1
        );
    }
    return myComplexFunctionImpl(
        nativeOrJsbiLib.subtract(m, my1),
        myComplexFunctionImpl(m, nativeOrJsbiLib.subtract(n, 1))
    );
}

//Takes native, JSBI polyfilled, or other polyfilled bigints
//Must return a `bigint` that may be native, polyfilled with JSBI, or polyfilled with other libraries
function myComplexFunction (m : bigint, n : bigint) : bigint {
    //Will be a native or JSBI polyfilled `bigint`
    const myM = nativeOrJsbiLib.BigInt(m.toString());
    const myN = nativeOrJsbiLib.BigInt(n.toString());
    const myResult = myComplexFunctionImpl(myM, myN);

    //Convert the result to a `bigint` type the same as its input
    return bigIntLib.BigInt(myResult.toString());
}

Using nativeOrJsbiLib saves the time needed to convert between JSBI and other polyfill libraries, if other polyfill libraries are used.


Polyfilling with node

  1. Have your polyfill code in a .js file.
  2. node -r my-polyfill.js my-entry-point.js

Polyfilling with ts-node

  1. Have your polyfill code in a .ts file.
  2. ts-node -r my-polyfill.ts my-entry-point.ts

Development

  1. git clone https://github.com/AnyhowStep/bigint-lib.git
  2. npm install
  3. npm run sanity-check to build and run tests.
  4. npm run to see a list of commands.
1.1.0

4 years ago

1.0.3

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago