Way to get number of digits in an int?

后端 未结 30 932
梦毁少年i
梦毁少年i 2020-11-22 17:21

Is there a neater way for getting the number of digits in an int than this method?

int numDigits = String.valueOf(1000).length();
相关标签:
30条回答
  • 2020-11-22 17:21

    Can I try? ;)

    based on Dirk's solution

    final int digits = number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number))));
    
    0 讨论(0)
  • 2020-11-22 17:22

    We can achieve this using a recursive loop

        public static int digitCount(int numberInput, int i) {
            while (numberInput > 0) {
            i++;
            numberInput = numberInput / 10;
            digitCount(numberInput, i);
            }
            return i;
        }
    
        public static void printString() {
            int numberInput = 1234567;
            int digitCount = digitCount(numberInput, 0);
    
            System.out.println("Count of digit in ["+numberInput+"] is ["+digitCount+"]");
        }
    
    0 讨论(0)
  • 2020-11-22 17:22

    Try converting the int to a string and then get the length of the string. That should get the length of the int.

    public static int intLength(int num){
        String n = Integer.toString(num);
        int newNum = n.length();
        return newNum;
    }
    
    0 讨论(0)
  • 2020-11-22 17:23

    The fastest approach: divide and conquer.

    Assuming your range is 0 to MAX_INT, then you have 1 to 10 digits. You can approach this interval using divide and conquer, with up to 4 comparisons per each input. First, you divide [1..10] into [1..5] and [6..10] with one comparison, and then each length 5 interval you divide using one comparison into one length 3 and one length 2 interval. The length 2 interval requires one more comparison (total 3 comparisons), the length 3 interval can be divided into length 1 interval (solution) and a length 2 interval. So, you need 3 or 4 comparisons.

    No divisions, no floating point operations, no expensive logarithms, only integer comparisons.

    Code (long but fast):

    if (n < 100000){
            // 5 or less
            if (n < 100){
                // 1 or 2
                if (n < 10)
                    return 1;
                else
                    return 2;
            }else{
                // 3 or 4 or 5
                if (n < 1000)
                    return 3;
                else{
                    // 4 or 5
                    if (n < 10000)
                        return 4;
                    else
                        return 5;
                }
            }
        } else {
            // 6 or more
            if (n < 10000000) {
                // 6 or 7
                if (n < 1000000)
                    return 6;
                else
                    return 7;
            } else {
                // 8 to 10
                if (n < 100000000)
                    return 8;
                else {
                    // 9 or 10
                    if (n < 1000000000)
                        return 9;
                    else
                        return 10;
                }
            }
        }
    

    Benchmark (after JVM warm-up) - see code below to see how the benchmark was run:

    1. baseline method (with String.length): 2145ms
    2. log10 method: 711ms = 3.02 times as fast as baseline
    3. repeated divide: 2797ms = 0.77 times as fast as baseline
    4. divide-and-conquer: 74ms = 28.99
      times as fast as baseline

    Full code:

    public static void main(String[] args)
    throws Exception
    {
    
        // validate methods:
        for (int i = 0; i < 1000; i++)
            if (method1(i) != method2(i))
                System.out.println(i);
        for (int i = 0; i < 1000; i++)
            if (method1(i) != method3(i))
                System.out.println(i + " " + method1(i) + " " + method3(i));
        for (int i = 333; i < 2000000000; i += 1000)
            if (method1(i) != method3(i))
                System.out.println(i + " " + method1(i) + " " + method3(i));
        for (int i = 0; i < 1000; i++)
            if (method1(i) != method4(i))
                System.out.println(i + " " + method1(i) + " " + method4(i));
        for (int i = 333; i < 2000000000; i += 1000)
            if (method1(i) != method4(i))
                System.out.println(i + " " + method1(i) + " " + method4(i));
    
        // work-up the JVM - make sure everything will be run in hot-spot mode
        allMethod1();
        allMethod2();
        allMethod3();
        allMethod4();
    
        // run benchmark
        Chronometer c;
    
        c = new Chronometer(true);
        allMethod1();
        c.stop();
        long baseline = c.getValue();
        System.out.println(c);
    
        c = new Chronometer(true);
        allMethod2();
        c.stop();
        System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");
    
        c = new Chronometer(true);
        allMethod3();
        c.stop();
        System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");
    
        c = new Chronometer(true);
        allMethod4();
        c.stop();
        System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");
    }
    
    
    private static int method1(int n)
    {
        return Integer.toString(n).length();
    }
    private static int method2(int n)
    {
        if (n == 0)
            return 1;
        return (int)(Math.log10(n) + 1);
    }
    private static int method3(int n)
    {
        if (n == 0)
            return 1;
        int l;
        for (l = 0 ; n > 0 ;++l)
            n /= 10;
        return l;
    }
    private static int method4(int n)
    {
        if (n < 100000)
        {
            // 5 or less
            if (n < 100)
            {
                // 1 or 2
                if (n < 10)
                    return 1;
                else
                    return 2;
            }
            else
            {
                // 3 or 4 or 5
                if (n < 1000)
                    return 3;
                else
                {
                    // 4 or 5
                    if (n < 10000)
                        return 4;
                    else
                        return 5;
                }
            }
        }
        else
        {
            // 6 or more
            if (n < 10000000)
            {
                // 6 or 7
                if (n < 1000000)
                    return 6;
                else
                    return 7;
            }
            else
            {
                // 8 to 10
                if (n < 100000000)
                    return 8;
                else
                {
                    // 9 or 10
                    if (n < 1000000000)
                        return 9;
                    else
                        return 10;
                }
            }
        }
    }
    
    
    private static int allMethod1()
    {
        int x = 0;
        for (int i = 0; i < 1000; i++)
            x = method1(i);
        for (int i = 1000; i < 100000; i += 10)
            x = method1(i);
        for (int i = 100000; i < 1000000; i += 100)
            x = method1(i);
        for (int i = 1000000; i < 2000000000; i += 200)
            x = method1(i);
    
        return x;
    }
    private static int allMethod2()
    {
        int x = 0;
        for (int i = 0; i < 1000; i++)
            x = method2(i);
        for (int i = 1000; i < 100000; i += 10)
            x = method2(i);
        for (int i = 100000; i < 1000000; i += 100)
            x = method2(i);
        for (int i = 1000000; i < 2000000000; i += 200)
            x = method2(i);
    
        return x;
    }
    private static int allMethod3()
    {
        int x = 0;
        for (int i = 0; i < 1000; i++)
            x = method3(i);
        for (int i = 1000; i < 100000; i += 10)
            x = method3(i);
        for (int i = 100000; i < 1000000; i += 100)
            x = method3(i);
        for (int i = 1000000; i < 2000000000; i += 200)
            x = method3(i);
    
        return x;
    }
    private static int allMethod4()
    {
        int x = 0;
        for (int i = 0; i < 1000; i++)
            x = method4(i);
        for (int i = 1000; i < 100000; i += 10)
            x = method4(i);
        for (int i = 100000; i < 1000000; i += 100)
            x = method4(i);
        for (int i = 1000000; i < 2000000000; i += 200)
            x = method4(i);
    
        return x;
    }
    

    Again, benchmark:

    1. baseline method (with String.length): 2145ms
    2. log10 method: 711ms = 3.02 times as fast as baseline
    3. repeated divide: 2797ms = 0.77 times as fast as baseline
    4. divide-and-conquer: 74ms = 28.99
      times as fast as baseline

    Edit: After I wrote the benchmark, I took a sneak peak into Integer.toString from Java 6, and I found that it uses:

    final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                      99999999, 999999999, Integer.MAX_VALUE };
    
    // Requires positive x
    static int stringSize(int x) {
        for (int i=0; ; i++)
            if (x <= sizeTable[i])
                return i+1;
    }
    

    I benchmarked it against my divide-and-conquer solution:

    1. divide-and-conquer: 104ms
    2. Java 6 solution - iterate and compare: 406ms

    Mine is about 4x as fast as the Java 6 solution.

    0 讨论(0)
  • 2020-11-22 17:24

    Marian's solution adapted for long type numbers (up to 9,223,372,036,854,775,807), in case someone want's to Copy&Paste it. In the program I wrote this for numbers up to 10000 were much more probable, so I made a specific branch for them. Anyway it won't make a significative difference.

    public static int numberOfDigits (long n) {     
        // Guessing 4 digit numbers will be more probable.
        // They are set in the first branch.
        if (n < 10000L) { // from 1 to 4
            if (n < 100L) { // 1 or 2
                if (n < 10L) {
                    return 1;
                } else {
                    return 2;
                }
            } else { // 3 or 4
                if (n < 1000L) {
                    return 3;
                } else {
                    return 4;
                }
            }           
        } else  { // from 5 a 20 (albeit longs can't have more than 18 or 19)
            if (n < 1000000000000L) { // from 5 to 12
                if (n < 100000000L) { // from 5 to 8
                    if (n < 1000000L) { // 5 or 6
                        if (n < 100000L) {
                            return 5;
                        } else {
                            return 6;
                        }
                    } else { // 7 u 8
                        if (n < 10000000L) {
                            return 7;
                        } else {
                            return 8;
                        }
                    }
                } else { // from 9 to 12
                    if (n < 10000000000L) { // 9 or 10
                        if (n < 1000000000L) {
                            return 9;
                        } else {
                            return 10;
                        }
                    } else { // 11 or 12
                        if (n < 100000000000L) {
                            return 11;
                        } else {
                            return 12;
                        }
                    }
                }
            } else { // from 13 to ... (18 or 20)
                if (n < 10000000000000000L) { // from 13 to 16
                    if (n < 100000000000000L) { // 13 or 14
                        if (n < 10000000000000L) { 
                            return 13;
                        } else {
                            return 14;
                        }
                    } else { // 15 or 16
                        if (n < 1000000000000000L) {
                            return 15;
                        } else {
                            return 16;
                        }
                    }
                } else { // from 17 to ...¿20?
                    if (n < 1000000000000000000L) { // 17 or 18
                        if (n < 100000000000000000L) {
                            return 17;
                        } else {
                            return 18;
                        }
                    } else { // 19? Can it be?
                        // 10000000000000000000L is'nt a valid long.
                        return 19;
                    }
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 17:24

    One wants to do this mostly because he/she wants to "present" it, which mostly mean it finally needs to be "toString-ed" (or transformed in another way) explicitly or implicitly anyway; before it can be presented (printed for example).

    If that is the case then just try to make the necessary "toString" explicit and count the bits.

    0 讨论(0)
提交回复
热议问题