BigInteger: count the number of decimal digits in a scalable method

Geoffrey De Smet picture Geoffrey De Smet · Sep 16, 2013 · Viewed 15.8k times · Source

I need the count the number of decimal digits of a BigInteger. For example:

  • 99 returns 2
  • 1234 returns 4
  • 9999 returns 4
  • 12345678901234567890 returns 20

I need to do this for a BigInteger with 184948 decimal digits and more. How can I do this fast and scalable?

The convert-to-String approach is slow:

public String getWritableNumber(BigInteger number) {
   // Takes over 30 seconds for 184948 decimal digits
   return "10^" + (number.toString().length() - 1);
}

This loop-devide-by-ten approach is even slower:

public String getWritableNumber(BigInteger number) {
    int digitSize = 0;
    while (!number.equals(BigInteger.ZERO)) {
        number = number.divide(BigInteger.TEN);
        digitSize++;
    }
    return "10^" + (digitSize - 1);
}

Are there any faster methods?

Answer

dln385 picture dln385 · May 21, 2014

Here's a fast method based on Dariusz's answer:

public static int getDigitCount(BigInteger number) {
  double factor = Math.log(2) / Math.log(10);
  int digitCount = (int) (factor * number.bitLength() + 1);
  if (BigInteger.TEN.pow(digitCount - 1).compareTo(number) > 0) {
    return digitCount - 1;
  }
  return digitCount;
}

The following code tests the numbers 1, 9, 10, 99, 100, 999, 1000, etc. all the way to ten-thousand digits:

public static void test() {
  for (int i = 0; i < 10000; i++) {
    BigInteger n = BigInteger.TEN.pow(i);
    if (getDigitCount(n.subtract(BigInteger.ONE)) != i || getDigitCount(n) != i + 1) {
      System.out.println("Failure: " + i);
    }
  }
  System.out.println("Done");
}

This can check a BigInteger with 184,948 decimal digits and more in well under a second.