g | x | w | all
Bytes Lang Time Link
331JavaScript Node.js240610T004053ZArnauld
nan240610T141442Z138 Aspe
nan240610T094056Zcorvus_1

JavaScript (Node.js), ≈3.3ms (1)

This hexadecimal version was suggested by tsh

Expects a BigInt.

This computes hammingweight(XOR(n, 3*n)), as suggested on A007302.

function f(binStr) {
  const tableHex = [
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 2, 3, 2, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  ];

  const n = BigInt("0b" + binStr);
  const hex = (n ^ 3n * n).toString(16);
  let count = 0;
  for (let i = 0, l = hex.length; i < l; ++i) {
    count += tableHex[hex.charCodeAt(i)];
  }
  return count;
}

Try it online!


Using binary, ≈16ms (1)

function f(binStr) {
  const n = BigInt("0b" + binStr);
  let bin = (n ^ 3n * n).toString(2);

  return bin.split("1").length - 1;
}

Try it online!

Bitwise approach, ≈12 seconds (1)

Converting to a binary or hexadecimal string and iterating over its characters may not be the most elegant method (conceptually speaking), but it's much, much faster than going bitwise.

I assume this one causes several new BigInts to be allocated, inducing a massive overhead in the pipeline when n is large.

function f(binStr) {
  const n = BigInt("0b" + binStr);
  let N = n ^ 3n * n,
      count = 0;

  while(N) {
    N &= N - 1n;
    count++;
  }
  return count;
}

Try it online!


(1) All benchmarks were done on my laptop with Node 20.10.0, using several calls to the function in a loop.

Python + gmpy2   2.1.5

import gmpy2
from gmpy2 import mpz
import time

def main():
    input_value = mpz('9515985770616618967204423793474873711653') * (mpz(10) ** 300990)
    print(f(input_value))

def f(n):
    bin_value = n ^ (n + (n << 1))
    return gmpy2.popcount(bin_value)

if __name__ == "__main__":
    start_time=time.time()
    main()
    print(f"{(time.time()-start_time)*1000} ms")

It is around 16ms on my machine.

Rust + num_bigint 0.4.5

use num_bigint::BigUint;
use std::str::FromStr;

fn main() {
    let input = BigUint::from_str("9515985770616618967204423793474873711653").unwrap()
        * (BigUint::from(10u64).pow(300990));
    print!("{}", f(input))
}

fn f(n: BigUint) -> u64 {
    let bin: BigUint = &n ^ (&n + (&n << 1));
    bin.count_ones()
}

For the best performance, make sure to compile with
RUSTFLAGS='-C target-cpu=native' cargo build --release. It is around 20ms on my machine.