Search code examples
javascriptbigintegerlogarithmbigint

Logarithm of a BigInt


Is there a way to get the logarithm of a BigInt in JavaScript?

With normal numbers, you would use this code:

const largeNumber = 1000;
const result = Math.log(largeNumber);

However, I need to work with factorial numbers, potentially higher than 170!, so the regular number type doesn't work. Math.log doesn't work with BigInt. So how do I get the logarithm?

const largeNumber = BigInt(1000);
const result = ???

Solution

  • In case you don't want to return a BigInt, then the following might work for you too:

    function log10(bigint) {
      if (bigint < 0) return NaN;
      const s = bigint.toString(10);
    
      return s.length + Math.log10("0." + s.substring(0, 15))
    }
    
    function log(bigint) {
      return log10(bigint) * Math.log(10);
    }
    
    function natlog(bigint) {
      if (bigint < 0) return NaN;
    
      const s = bigint.toString(16);
      const s15 = s.substring(0, 15);
    
      return Math.log(16) * (s.length - s15.length) + Math.log("0x" + s15);
    }
    
    const largeNumber = BigInt('9039845039485903949384755723427863486200719925474009384509283489374539477777093824750398247503894750384750238947502389475029384755555555555555555555555555555555555555554444444444444444444444444222222222222222222222255666666666666938475938475938475938408932475023847502384750923847502389475023987450238947509238475092384750923847502389457028394750293847509384570238497575938475938475938475938475555555555559843991');
    
    console.log(natlog(largeNumber)); // 948.5641152531601
    console.log(log10(largeNumber), log(largeNumber), log(-1))
    // 411.95616098588766
    // 948.5641152531603
    // NaN

    log10() will return a standard precision float for any BigInt or Int number you enter as an argument.


    As @Mielipuoli quite rightly mentioned, the natural logarithm can be calculated as

    function log(bigint) {
      return log10(bigint) / Math.log10(Math.E);
    }
    

    Or, even simpler, as shown in my snippet above, as log10(bigint) * Math.log(10).

    @Nat already explained in a comment below, how this approach works, i.e. by calculating the integer and fractional parts of the logarithm separately and summing them up. With regards to the precision of the result: the Math.log10() works on a float number with its usual 13 to 14 decimal digits precision, and so, for a result, this is all you can expect too.

    For this reason, I truncated the string representation of the BigInt number to 15 characters. Any further decimal places would have been ignored in the implicit type conversion to float anyway.

    I also added the hex-string version here, suggested by @PeterCordes and further developed by @somebody as natlog(). It works - probably faster than my original solution - and produces the "same" result (only the very last shown digit deviates between the two results)!