6

This is the naive algorithm that calculates integer log2(n),

  function ilog2(n) {  // n is a positive non-zero BigInt
     const C1 = BigInt(1)
     const C2 = BigInt(2)
     for(var count=0; n>C1; count++)  n = n/C2
     return count
  } // example ilog2(16n)==4

I am testing optimizations (see example below) but they are not "for log2", as commented here.

There are something better using WebAssembly?

PS: if it is not possible a generic solution, to solve my problem I can use functions like ilog2_64bits(n), with WebAssembly truncating or ignoring some bits of input BigInt.


non-WebAssembly

Example of not so optimized in pure Javascript (ideal is WebAssembly!)... Trying adaptation of integerLogarithm() of BigInteger.js:

  function ilog2_pe(value, base=2n) {
      // example: ilog2_pe(255n) returns { p: 128n, e: 7n }
      if (base  <= value) {
          let i = ilog2_pe(value, base**2n);
          let t = i.p*base
          return (t <= value)
            ? { p: t,   e: i.e*2n + 1n }
            : { p: i.p, e: i.e*2n }
      }
      return { p: 1n, e: 0n };
  }

  function ilog2_str(n) { // 2*faster!
    return n.toString(2).length - 1
  }

PS: it is running in modern browsers and last versions of NodeJS.


About performance... ilog2_pe(x64bits) is 4 times faster tham the naive ilog2(), ilog2_pe(x1024bits) is ~9 times faster... Was expected... But:

Any non-WebAssembly solution has so ugly performance, even for 512, 1024, 2048 bits... counting string digits with ilog_str() is 2 times faster! For less tham 64 bits is 3 or more times faster.

Peter Krauss
  • 13,174
  • 24
  • 167
  • 304

1 Answers1

0

The following code seems faster than ilog2_str on Firfeox 89, Chrome 90.

function ilog2_str(n) { // 2*faster!
  return n.toString(2).length - 1
}

function ilog2_bs(value) {
  let result = 0n, i, v;
  for (i = 1n; value >> (1n << i); i <<= 1n);
  while (value > 1n) {
    v = 1n << --i;
    if (value >> v) {
      result += v;
      value >>= v;
    }
  }
  return result;
}

testcases = [...Array(10000)].map((n, i) => 13n ** BigInt(i));
testcases.map(ilog2_str);
testcases.map(ilog2_bs);

though I don't know why.

tsh
  • 4,263
  • 5
  • 28
  • 47