Skip to content

Getting started in JavaScript

The kt-math npm package brings Kt-Math to JavaScript (Node.js and browsers). Its BigIntegers are thin wrappers of native BigInts; its BigDecimals and BigRationals are the Kotlin implementation, on top of them.

Install

npm install kt-math

Import

kt-math is an ES module (require("kt-math") works too, on Node.js 20.19+ and 22.12+), exporting every class and function under its own name. The bigInteger, bigDecimal and bigRational functions accept any JS value (strings, numbers, BigInts, arrays of arguments); the classes have static factories (BigInteger.of, BigDecimal.parse, ...) and constants (BigInteger.TEN, MathContext.DECIMAL64, ...). The package ships TypeScript definitions.

import {
  BigInteger, BigDecimal, BigRational, BigComplex, BigFactory, BigIntegerRange, MathContext, RoundingMode,
  bigInteger, bigDecimal, bigRational, pi, log,
} from "kt-math";

Integers

Kotlin's operators are methods (plus, times, ...); overloads have distinct names (plusInt, timesLong, ...). Longs are native BigInts:

  const x = bigInteger("123456789012345678901234567890");
  const y = bigInteger(42);
  assert.equal(x.plus(y).toString(), "123456789012345678901234567932");
  assert.equal(x.times(y).toString(), "5185185138518518513851851851380");
  assert.equal(x.div(y).toString(), "2939447357436801878600823045");
  assert.equal(x.rem(bigInteger(11)).toString(), "7");
  assert.equal(x.plusInt(1).toString(), "123456789012345678901234567891");
  assert.equal(bigInteger(["ff", 16]).toString(), "255");
  assert.equal(bigInteger(12n).toString(), "12"); // native BigInts are accepted...
  assert.equal(typeof y.toLong(), "bigint"); // ...and Kotlin Longs are BigInts
  assert.equal(y.toLong(), 42n);
  assert.equal(BigInteger.parseWithRadix("-ff", 16).toString(), "-255");
  assert.ok(x.compareTo(y) > 0);
  assert.ok(bigInteger(12).equals(BigInteger.of(12)));
  assert.equal(BigInteger.TEN.pow(3).toString(), "1000");

Errors

Kotlin exceptions are JS Errors, whose class name is the Kotlin one:

  assert.throws(() => bigInteger(1).div(BigInteger.ZERO), { name: "ArithmeticException" });
  assert.throws(() => bigInteger("12x"), (e) => e instanceof Error && e.constructor.name === "NumberFormatException");

Decimals

  const a = bigDecimal("1.10");
  const b = bigDecimal(3);
  assert.equal(a.plus(b).toString(), "4.10");
  assert.equal(a.divWithContext(b, new MathContext(10, RoundingMode.HALF_EVEN)).toString(), "0.3666666667");
  assert.equal(a.divWithScale(b, 2, RoundingMode.HALF_UP).toString(), "0.37");
  assert.equal(bigDecimal(["1234.5", new MathContext(2)]).toString(), "1.2E+3");
  assert.equal(bigDecimal(0.1).toString(), "0.1"); // JS numbers go through their string representation
  assert.equal(BigDecimal.valueOfDouble(0.1).toString(), "0.1");
  assert.equal(bigDecimal(2).sqrt(new MathContext(10)).toString(), "1.414213562");
  assert.equal(bigDecimal("1.0").compareTo(bigDecimal("1.00")), 0); // equal values, while equals checks scales too
  assert.ok(!bigDecimal("1.0").equals(bigDecimal("1.00")));
  assert.throws(() => BigDecimal.ONE.div(b), { name: "ArithmeticException" }); // 1/3 isn't exact

Rationals

  const third = bigRational("1/3");
  const sum = third.plus(bigRational([1, 6]));
  assert.equal(sum.reduce().toRationalString(), "1/2");
  assert.equal(sum.toBigDecimalWithContext(new MathContext(3)).toString(), "0.5"); // exact: no trailing zeros
  assert.equal(BigRational.ofFraction(37, 3).toBigInteger().toString(), "12");
  assert.equal(third.timesInt(3).compareTo(BigRational.ONE), 0);

Functions

big-math's functions take the BigDecimal as their first argument (they are extension functions in Kotlin):

  const digits = new MathContext(20);
  assert.equal(pi(digits).toString(), "3.1415926535897932385");
  assert.equal(log(bigDecimal(2), digits).toString(), "0.69314718055994530942"); // log(x, mc): x.log(mc) in Kotlin
  assert.equal(bigDecimal(2).sqrt(digits).toString(), "1.4142135623730950488"); // a method, as in Kotlin

The factory

  const factory = BigFactory.DEFAULT;
  assert.equal(factory.parseBigInteger("-ff", 16).toString(), "-255");
  assert.equal(factory.parseBigIntegerOrNull("ff", 10), null);
  assert.equal(factory.parseBigDecimal("1234", new MathContext(2)).toString(), "1.2E+3");
  assert.equal(factory.parseBigRationalOrNull("1/0"), null);
  assert.equal(factory.bigRationalOfInts(2, 6).reduce().toRationalString(), "1/3");
  assert.equal(factory.probablePrime(64).bitLength, 64);