5

I want to use Number.toString(62) but ECMAScript does not support it (only support radix from 2 to 36), so I'm writing myself version of Number.toString.

And I only need to use it to format int64, do not need to care about double.

So, I benched the native methods for Number and BigInt with different radix.

The bench code as follow:

import { Suite } from 'benchmark';
import { shuffle } from 'lodash';

const float = new Array(10000)
  .fill(0)
  .map(() => Math.random() * Number.MAX_SAFE_INTEGER);
const int = float.map(Math.floor);
const big = int.map(BigInt);

export const suite = new Suite('native integer format')
  .add('Int64.toString(10)', () => shuffle(int).map((n) => n.toString(10)))
  .add('Int64.toString(16)', () => shuffle(int).map((n) => n.toString(16)))
  .add('Int64.toString(36)', () => shuffle(int).map((n) => n.toString(36)))
  .add('Float64.toString(10)', () => shuffle(float).map((n) => n.toString(10)))
  .add('Float64.toString(16)', () => shuffle(float).map((n) => n.toString(16)))
  .add('Float64.toString(36)', () => shuffle(float).map((n) => n.toString(36)))
  .add('BigInt.toString(10)', () => shuffle(big).map((n) => n.toString(10)))
  .add('BigInt.toString(16)', () => shuffle(big).map((n) => n.toString(16)))
  .add('BigInt.toString(36)', () => shuffle(big).map((n) => n.toString(36)))
  .add('Date.now()', () => shuffle(int).map(Date.now));

The result is:

native integer format -> Int64.toString(10) x 660 ops/sec ±2.82% (83 runs sampled)
native integer format -> Int64.toString(16) x 109 ops/sec ±0.66% (79 runs sampled)
native integer format -> Int64.toString(36) x 134 ops/sec ±0.42% (84 runs sampled)
native integer format -> Float64.toString(10) x 448 ops/sec ±2.49% (85 runs sampled)
native integer format -> Float64.toString(16) x 103 ops/sec ±1.15% (75 runs sampled)
native integer format -> Float64.toString(36) x 130 ops/sec ±1.36% (83 runs sampled)
native integer format -> BigInt.toString(10) x 424 ops/sec ±0.64% (92 runs sampled)
native integer format -> BigInt.toString(16) x 1,039 ops/sec ±1.86% (92 runs sampled)
native integer format -> BigInt.toString(36) x 532 ops/sec ±0.76% (92 runs sampled)
native integer format -> Date.now() x 1,163 ops/sec ±0.59% (93 runs sampled)

As you see it upon, the BigInt.toString(16) is the fastest one(except for Date.now, which is the object to reference).

The performance of mine is a little big faster than Int64.toString.

Is there any open source code or known algorithm to speed up it?

And there is something interesting: the fastest one of Number.toString(radix) is Number.toString(10), but it is toString(16) for BigInt. Is it a magic?

acrazing
  • 1,955
  • 16
  • 24
  • 1
    "*the fastest one of `Number.toString(radix)` is `Number.toString(10)`*" probably becaust the overwhelming majority of time your code (not even you) would be calling `Number.toString()` which is implicitly `Number.toString(10)`. So it makes sense to optimise for that. `BigInt` might be using some generic implementation that doesn't optimise for base 10. Given that it's base 16, I'd guess that it's powers of 2 that are faster in general. – VLAZ Apr 04 '19 at 06:17
  • The benchmark is wrong by design. Since toString is fast, you're mostly testing Lodash shuffle and array `map`, the error may accumulate and give odd results. Leave loops to Benchmark.js. – Estus Flask Apr 04 '19 at 06:39
  • See also [Fastest way to convert a number to radix 64 in JavaScript](https://stackoverflow.com/q/6213227/519360), which isn't quite a duplicate, but since you have to quote it anyway, you might as well use a power of two for speed. – Adam Katz Apr 02 '22 at 03:14

0 Answers0