简体   繁体   English

获取int中位数的方法?

[英]Way to get number of digits in an int?

Is there a neater way for getting the number of digits in an int than this method?有没有比这种方法更简洁的方法来获取 int 中的位数?

int numDigits = String.valueOf(1000).length();

Your String-based solution is perfectly OK, there is nothing "un-neat" about it.您的基于字符串的解决方案非常好,没有什么“不整洁”的地方。 You have to realize that mathematically, numbers don't have a length, nor do they have digits.你必须意识到,在数学上,数字没有长度,也没有数字。 Length and digits are both properties of a physical representation of a number in a specific base, ie a String.长度和数字都是特定基数(即字符串)中数字的物理表示的属性。

A logarithm-based solution does (some of) the same things the String-based one does internally, and probably does so (insignificantly) faster because it only produces the length and ignores the digits.基于对数的解决方案(某些)与基于字符串的解决方案在内部执行的操作相同,并且可能执行速度更快(微不足道),因为它只产生长度并忽略数字。 But I wouldn't actually consider it clearer in intent - and that's the most important factor.但我实际上不会认为它的意图更清晰 - 这是最重要的因素。

The logarithm is your friend:对数是你的朋友:

int n = 1000;
int length = (int)(Math.log10(n)+1);

NB: only valid for n > 0.注意:仅对 n > 0 有效。

The fastest approach: divide and conquer.最快的方法:分而治之。

Assuming your range is 0 to MAX_INT, then you have 1 to 10 digits.假设您的范围是 0 到 MAX_INT,那么您有 1 到 10 位数字。 You can approach this interval using divide and conquer, with up to 4 comparisons per each input.您可以使用分治法来接近此间隔,每个输入最多进行 4 次比较。 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.首先,通过一次比较将 [1..10] 划分为 [1..5] 和 [6..10],然后使用一次比较将每个长度为 5 的区间划分为一个长度为 3 的区间和一个长度为 2 的区间。 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.长度为2的区间需要多比较一次(共3次比较),长度为3的区间可分为长度为1的区间(解)和长度为2的区间。 So, you need 3 or 4 comparisons.因此,您需要进行 3 或 4 次比较。

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:基准测试(在 JVM 预热之后) - 请参阅下面的代码以了解基准测试是如何运行的:

  1. baseline method (with String.length): 2145ms基线方法(使用 String.length):2145ms
  2. log10 method: 711ms = 3.02 times as fast as baseline log10 方法:711ms = 3.02 倍于基线
  3. repeated divide: 2797ms = 0.77 times as fast as baseline重复除法:2797ms = 0.77 倍于基线
  4. divide-and-conquer: 74ms = 28.99分而治之: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基线方法(使用 String.length):2145ms
  2. log10 method: 711ms = 3.02 times as fast as baseline log10 方法:711ms = 3.02 倍于基线
  3. repeated divide: 2797ms = 0.77 times as fast as baseline重复除法:2797ms = 0.77 倍于基线
  4. divide-and-conquer: 74ms = 28.99 times as fast as baseline分而治之:74ms = 28.99 倍于基线

Edit编辑

After I wrote the benchmark, I took a sneak peak into Integer.toString from Java 6, and I found that it uses:在我编写了基准测试之后,我从 Java 6 中偷偷摸摸到了 Integer.toString,我发现它使用了:

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分而治之:104ms
  2. Java 6 solution - iterate and compare: 406ms Java 6 解决方案 - 迭代和比较:406ms

Mine is about 4x as fast as the Java 6 solution.我的速度大约是 Java 6 解决方案的 4 倍。

Two comments on your benchmark: Java is a complex environment, what with just-in-time compiling and garbage collection and so forth, so to get a fair comparison, whenever I run a benchmark, I always: (a) enclose the two tests in a loop that runs them in sequence 5 or 10 times.关于您的基准测试的两条评论:Java 是一个复杂的环境,需要即时编译和垃圾收集等等,所以为了公平比较,每当我运行基准测试时,我总是:(a)附上两个测试在按顺序运行它们 5 或 10 次的循环中。 Quite often the runtime on the second pass through the loop is quite different from the first.很多时候,第二次循环的运行时间与第一次完全不同。 And (b) After each "approach", I do a System.gc() to try to trigger a garbage collection.并且 (b) 在每次“方法”之后,我都会执行 System.gc() 来尝试触发垃圾收集。 Otherwise, the first approach might generate a bunch of objects, but not quite enough to force a garbage collection, then the second approach creates a few objects, the heap is exhausted, and garbage collection runs.否则,第一种方法可能会生成一堆对象,但不足以强制进行垃圾回收,然后第二种方法会创建一些对象,堆耗尽,然后垃圾回收运行。 Then the second approach is "charged" for picking up the garbage left by the first approach.然后第二种方法是“收费”的,用于拾取第一种方法留下的垃圾。 Very unfair!很不公平!

That said, neither of the above made a significant difference in this example.也就是说,以上都没有在这个例子中产生显着差异。

With or without those modifications, I got very different results than you did.无论有没有这些修改,我得到的结果都与你不同。 When I ran this, yes, the toString approach gave run times of 6400 to 6600 millis, while the log approach topok 20,000 to 20,400 millis.当我运行它时,是的,toString 方法的运行时间为 6400 到 6600 毫秒,而 log 方法的运行时间为 20,000 到 20,400 毫秒。 Instead of being slightly faster, the log approach was 3 times slower for me.日志方法不是稍微快一点,而是对我来说慢了 3 倍。

Note that the two approaches involve very different costs, so this isn't totally shocking: The toString approach will create a lot of temporary objects that have to be cleaned up, while the log approach takes more intense computation.请注意,这两种方法涉及非常不同的成本,因此这并不完全令人震惊:toString 方法将创建许多必须清理的临时对象,而 log 方法需要更密集的计算。 So maybe the difference is that on a machine with less memory, toString requires more garbage collection rounds, while on a machine with a slower processor, the extra computation of log would be more painful.所以也许区别在于,在内存较少的机器上,toString 需要更多的垃圾收集轮次,而在处理器较慢的机器上,额外的日志计算会更痛苦。

I also tried a third approach.我还尝试了第三种方法。 I wrote this little function:我写了这个小函数:

static int numlength(int n)
{
    if (n == 0) return 1;
    int l;
    n=Math.abs(n);
    for (l=0;n>0;++l)
        n/=10;
    return l;           
}

That ran in 1600 to 1900 millis -- less than 1/3 of the toString approach, and 1/10 the log approach on my machine.运行时间为 1600 到 1900 毫秒——不到 toString 方法的 1/3,以及我机器上的 log 方法的 1/10。

If you had a broad range of numbers, you could speed it up further by starting out dividing by 1,000 or 1,000,000 to reduce the number of times through the loop.如果您的数字范围很广,则可以通过开始除以 1,000 或 1,000,000 以减少循环次数来进一步加快速度。 I haven't played with that.我没玩过那个。

Can't leave a comment yet, so I'll post as a separate answer.还不能发表评论,所以我将作为单独的答案发布。

The logarithm-based solution doesn't calculate the correct number of digits for very big long integers, for example:基于对数的解决方案不会为非常大的长整数计算正确的位数,例如:

long n = 99999999999999999L;

// correct answer: 17
int numberOfDigits = String.valueOf(n).length();

// incorrect answer: 18
int wrongNumberOfDigits = (int) (Math.log10(n) + 1); 

Logarithm-based solution calculates incorrect number of digits in large integers 基于对数的解决方案计算大整数中不正确的位数

Using Java使用 Java

int nDigits = Math.floor(Math.log10(Math.abs(the_integer))) + 1;

use import java.lang.Math.*;使用import java.lang.Math.*; in the beginning在一开始的时候

Using C使用 C

int nDigits = floor(log10(abs(the_integer))) + 1;

use inclue math.h in the beginning在开头使用inclue math.h

Since the number of digits in base 10 of an integer is just 1 + truncate(log10(number)) , you can do:由于整数的以 10 为底的位数仅为1 + truncate(log10(number)) ,因此您可以执行以下操作:

public class Test {

    public static void main(String[] args) {

        final int number = 1234;
        final int digits = 1 + (int)Math.floor(Math.log10(number));

        System.out.println(digits);
    }
}

Edited because my last edit fixed the code example, but not the description.编辑是因为我上次编辑修复了代码示例,但没有修复描述。

Another string approach.另一种字符串方法。 Short and sweet - for any integer n .简短而甜蜜 - 对于任何整数n

int length = ("" + n).length();

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. Marian 的解决方案适用于类型数字(最多 9,223,372,036,854,775,807),以防有人想要复制和粘贴它。 In the program I wrote this for numbers up to 10000 were much more probable, so I made a specific branch for them.在我编写的程序中,高达 10000 的数字更有可能,所以我为它们做了一个特定的分支。 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;
                }
            }
        }
    }
}

How about plain old Mathematics?普通的旧数学怎么样? Divide by 10 until you reach 0.除以 10 直到达到 0。

public static int getSize(long number) {
        int count = 0;
        while (number > 0) {
            count += 1;
            number = (number / 10);
        }
        return count;
    }

Can I try?我可以试试吗? ;) ;)

based on Dirk's solution基于 Dirk 的解决方案

final int digits = number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number))));

Marian's Solution, now with Ternary:玛丽安的解决方案,现在使用三元:

 public int len(int n){
        return (n<100000)?((n<100)?((n<10)?1:2):(n<1000)?3:((n<10000)?4:5)):((n<10000000)?((n<1000000)?6:7):((n<100000000)?8:((n<1000000000)?9:10)));
    }

Because we can.因为我们可以。

I see people using String libraries or even using the Integer class.我看到人们使用 String 库,甚至使用 Integer 类。 Nothing wrong with that but the algorithm for getting the number of digits is not that complicated.这没有错,但获取位数的算法并不复杂。 I am using a long in this example but it works just as fine with an int.我在这个例子中使用了 long 但它与 int 一样好。

 private static int getLength(long num) {

    int count = 1;

    while (num >= 10) {
        num = num / 10;
        count++;
    }

    return count;
}

no String API, no utils, no type conversion, just pure java iteration ->没有 String API,没有 utils,没有类型转换,只是纯 java 迭代 ->

public static int getNumberOfDigits(int input) {
    int numOfDigits = 1;
    int base = 1;
    while (input >= base * 10) {
        base = base * 10;
        numOfDigits++;
    }
    return numOfDigits;
 }

You can go long for bigger values if you please.如果你愿意,你可以长期追求更大的价值。

Curious, I tried to benchmark it ...好奇,我试图对其进行基准测试...

import org.junit.Test;
import static org.junit.Assert.*;


public class TestStack1306727 {

    @Test
    public void bench(){
        int number=1000;
        int a= String.valueOf(number).length();
        int b= 1 + (int)Math.floor(Math.log10(number));

        assertEquals(a,b);
        int i=0;
        int s=0;
        long startTime = System.currentTimeMillis();
        for(i=0, s=0; i< 100000000; i++){
            a= String.valueOf(number).length();
            s+=a;
        }
        long stopTime = System.currentTimeMillis();
        long runTime = stopTime - startTime;
        System.out.println("Run time 1: " + runTime);
        System.out.println("s: "+s);
        startTime = System.currentTimeMillis();
        for(i=0,s=0; i< 100000000; i++){
            b= number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number))));
            s+=b;
        }
        stopTime = System.currentTimeMillis();
        runTime = stopTime - startTime;
        System.out.println("Run time 2: " + runTime);
        System.out.println("s: "+s);
        assertEquals(a,b);


    }
}

the results are :结果是:

Run time 1: 6765
s: 400000000
Run time 2: 6000
s: 400000000

Now I am left to wonder if my benchmark actually means something but I do get consistent results (variations within a ms) over multiple runs of the benchmark itself ... :) It looks like it's useless to try and optimize this...现在我想知道我的基准测试是否真的意味着什么,但我确实在多次运行基准测试本身时得到了一致的结果(在一毫秒内的变化)...... :) 看起来尝试优化它是没有用的......


edit: following ptomli's comment, I replaced 'number' by 'i' in the code above and got the following results over 5 runs of the bench :编辑:根据 ptomli 的评论,我在上面的代码中将 'number' 替换为 'i' 并在 5 次运行中得到以下结果:

Run time 1: 11500
s: 788888890
Run time 2: 8547
s: 788888890

Run time 1: 11485
s: 788888890
Run time 2: 8547
s: 788888890

Run time 1: 11469
s: 788888890
Run time 2: 8547
s: 788888890

Run time 1: 11500
s: 788888890
Run time 2: 8547
s: 788888890

Run time 1: 11484
s: 788888890
Run time 2: 8547
s: 788888890

With design (based on problem).有设计(基于问题)。 This is an alternate of divide-and-conquer.这是分而治之的替代方案。 We'll first define an enum (considering it's only for an unsigned int).我们将首先定义一个枚举(考虑到它仅用于无符号整数)。

public enum IntegerLength {
    One((byte)1,10),
    Two((byte)2,100),
    Three((byte)3,1000),
    Four((byte)4,10000),
    Five((byte)5,100000),
    Six((byte)6,1000000),
    Seven((byte)7,10000000),
    Eight((byte)8,100000000),
    Nine((byte)9,1000000000);

    byte length;
    int value;

    IntegerLength(byte len,int value) {
        this.length = len;
        this.value = value;
    }

    public byte getLenght() {
        return length;
    }

    public int getValue() {
        return value;
    }
}

Now we'll define a class that goes through the values of the enum and compare and return the appropriate length.现在我们将定义一个遍历枚举值并比较并返回适当长度的类。

public class IntegerLenght {
    public static byte calculateIntLenght(int num) {    
        for(IntegerLength v : IntegerLength.values()) {
            if(num < v.getValue()){
                return v.getLenght();
            }
        }
        return 0;
    }
}

The run time of this solution is the same as the divide-and-conquer approach.该解决方案的运行时间与分治法相同。

What about this recursive method?这个递归方法怎么样?

    private static int length = 0;

    public static int length(int n) {
    length++;
    if((n / 10) < 10) {
        length++;
    } else {
        length(n / 10);
    }
    return length;
}

simple solution:简单的解决方案:

public class long_length {
    long x,l=1,n;
    for (n=10;n<x;n*=10){
        if (x/n!=0){
            l++;
        }
    }
    System.out.print(l);
}

A really simple solution:一个非常简单的解决方案:

public int numLength(int n) {
  for (int length = 1; n % Math.pow(10, length) != n; length++) {}
  return length;
}

Or instead the length you can check if the number is larger or smaller then the desired number.或者,您可以检查数字是大于还是小于所需数字的长度。

    public void createCard(int cardNumber, int cardStatus, int customerId) throws SQLException {
    if(cardDao.checkIfCardExists(cardNumber) == false) {
        if(cardDao.createCard(cardNumber, cardStatus, customerId) == true) {
            System.out.println("Card created successfully");
        } else {

        }
    } else {
        System.out.println("Card already exists, try with another Card Number");
        do {
            System.out.println("Enter your new Card Number: ");
            scan = new Scanner(System.in);
            int inputCardNumber = scan.nextInt();
            cardNumber = inputCardNumber;
        } while(cardNumber < 95000000);
        cardDao.createCard(cardNumber, cardStatus, customerId);
    }
}

} }

I haven't seen a multiplication-based solution yet.我还没有看到基于乘法的解决方案。 Logarithm, divison, and string-based solutions will become rather unwieldy against millions of test cases, so here's one for ints :对于数百万个测试用例,对数、除法和基于字符串的解决方案将变得相当笨拙,所以这里有一个ints

/**
 * Returns the number of digits needed to represents an {@code int} value in 
 * the given radix, disregarding any sign.
 */
public static int len(int n, int radix) {
    radixCheck(radix); 
    // if you want to establish some limitation other than radix > 2
    n = Math.abs(n);

    int len = 1;
    long min = radix - 1;

    while (n > min) {
        n -= min;
        min *= radix;
        len++;
    }

    return len;
}

In base 10, this works because n is essentially being compared to 9, 99, 999... as min is 9, 90, 900... and n is being subtracted by 9, 90, 900...在以 10 为底的情况下,这是有效的,因为 n 本质上是与 9、99、999... 进行比较,因为 min 是 9、90、900...,而 n 被 9、90、900...减去

Unfortunately, this is not portable to long just by replacing every instance of int due to overflow.不幸的是,由于溢出,仅通过替换int的每个实例就不能移植到long On the other hand, it just so happens it will work for bases 2 and 10 (but badly fails for most of the other bases).另一方面,它恰好适用于 2 号和 10 号基地(但对于大多数其他基地来说严重失败)。 You'll need a lookup table for the overflow points (or a division test... ew)您需要一个查找表来查找溢出点(或除法测试...... ew)

/**
 * For radices 2 &le r &le Character.MAX_VALUE (36)
 */
private static long[] overflowpt = {-1, -1, 4611686018427387904L,
    8105110306037952534L, 3458764513820540928L, 5960464477539062500L,
    3948651115268014080L, 3351275184499704042L, 8070450532247928832L,
    1200757082375992968L, 9000000000000000000L, 5054470284992937710L,
    2033726847845400576L, 7984999310198158092L, 2022385242251558912L,
    6130514465332031250L, 1080863910568919040L, 2694045224950414864L,
    6371827248895377408L, 756953702320627062L, 1556480000000000000L,
    3089447554782389220L, 5939011215544737792L, 482121737504447062L,
    839967991029301248L, 1430511474609375000L, 2385723916542054400L,
    3902460517721977146L, 6269893157408735232L, 341614273439763212L,
    513726300000000000L, 762254306892144930L, 1116892707587883008L,
    1617347408439258144L, 2316231840055068672L, 3282671350683593750L,
    4606759634479349760L};

public static int len(long n, int radix) {
    radixCheck(radix);
    n = abs(n);

    int len = 1;
    long min = radix - 1;
    while (n > min) {
        len++;
        if (min == overflowpt[radix]) break;
        n -= min;
        min *= radix;

    }

    return len;
}

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+"]");
    }

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;一个人想要这样做主要是因为他/她想“呈现”它,这主要意味着它最终需要显式或隐式地被“toString-ed”(或以另一种方式转换); 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.如果是这种情况,那么只需尝试明确必要的“toString”并计算位。

I wrote this function after looking Integer.java source code.我在查看Integer.java源代码后编写了这个函数。

private static int stringSize(int x) {
    final int[] sizeTable = {9, 99, 999, 9_999, 99_999, 999_999, 9_999_999,
            99_999_999, 999_999_999, Integer.MAX_VALUE};
    for (int i = 0; ; ++i) {
        if (x <= sizeTable[i]) {
            return i + 1;
        }
    }
}

One of the efficient ways to count the number of digits in an int variable would be to define a method digitsCounter with a required number of conditional statements.计算int变量中位数的有效方法之一是定义具有所需数量的条件语句的方法digitsCounter
The approach is simple, we will be checking for each range in which a n digit number can lie:方法很简单,我们将检查n位数字所在的每个范围:
0 : 9 are Single digit numbers 0 : 9是个Single
10 : 99 are Double digit numbers 10 : 99Double
100 : 999 are Triple digit numbers and so on... 100 : 999Triple等等...

    static int digitsCounter(int N)
    {   // N = Math.abs(N); // if `N` is -ve
        if (0 <= N && N <= 9) return 1;
        if (10 <= N && N <= 99) return 2;
        if (100 <= N && N <= 999) return 3;
        if (1000 <= N && N <= 9999) return 4;
        if (10000 <= N && N <= 99999) return 5;
        if (100000 <= N && N <= 999999) return 6;
        if (1000000 <= N && N <= 9999999) return 7;
        if (10000000 <= N && N <= 99999999) return 8;
        if (100000000 <= N && N <= 999999999) return 9;
        return 10;
    }

A cleaner way to do this is to remove the check for the lower limits as it won't be required if we proceed in a sequential manner.一种更简洁的方法是取消对下限的检查,因为如果我们以顺序方式进行,则不需要它。

    static int digitsCounter(int N)
    {
        N = N < 0 ? -N : N;
        if (N <= 9) return 1;
        if (N <= 99) return 2;
        if (N <= 999) return 3;
        if (N <= 9999) return 4;
        if (N <= 99999) return 5;
        if (N <= 999999) return 6;
        if (N <= 9999999) return 7;
        if (N <= 99999999) return 8;
        if (N <= 999999999) return 9;
        return 10; // Max possible digits in an 'int'
    }

Ideally, an integer divided by 10 multiple times will return the number of digits as long as the integer is not zero.理想情况下,只要整数不为零,整数除以 10 多次将返回位数。 As such a simple method to do so can be created as below.这样一个简单的方法可以创建如下。

public static int getNumberOfDigits(int number) {
    int numberOfDigits = 0;                
    while(number != 0) {
        number /= 10;
        numberOfDigits++;
    }
    
    return numberOfDigits;
}

It depends on what you mean by "neat".这取决于您所说的“整洁”是什么意思。 I think the following code is fairly neat, and it runs fast.我认为下面的代码相当简洁,而且运行速度很快。

It is based on Marian's answer , extended to work with all long values and rendered using the ? :它基于玛丽安的回答,扩展为使用所有long值并使用? : ? : operator. ? :运营商。

private static int numberOfDigits(final long n)
{
    return n == Long.MIN_VALUE ? 19 : n < 0l ? numberOfDigits(-n) :
            n < 100000000l ? // 1-8
              n < 10000l ? // 1-4
                n < 100l ? // 1-2
                  n < 10l ? 1 : 2 : // 1-2
                  n < 1000l ? 3 : 4 : // 3-4
                n < 1000000l ? // 5-8
                  n < 100000l ? 5 : 6 : // 5-6
                  n < 10000000l ? 7 : 8 : // 7-8
            n < 10000000000000000l ? // 9-16
              n < 1000000000000l ? // 9-12
                n < 10000000000l ? // 9-10
                  n < 1000000000l ? 9 : 10 : // 9-10
                  n < 100000000000l ? 11 : 12 : // 11-12
                n < 100000000000000l ? // 13-16
                  n < 10000000000000l ? 13 : 14 : // 13-14
                  n < 1000000000000000l ? 15 : 16 : // 15-16
                  n < 100000000000000000l ? 17 :  // 17-19
                  n < 1000000000000000000l ? 18 :
                  19;
}

是否有比此方法更整洁的方法来获取int中的位数?

int numDigits = String.valueOf(1000).length();

是否有比此方法更整洁的方法来获取int中的位数?

int numDigits = String.valueOf(1000).length();

Here's a really simple method I made that works for any number:这是我制作的一个非常简单的方法,适用于任何数字:

public static int numberLength(int userNumber) {

    int numberCounter = 10;
    boolean condition = true;
    int digitLength = 1;

    while (condition) {
        int numberRatio = userNumber / numberCounter;
        if (numberRatio < 1) {
            condition = false;
        } else {
            digitLength++;
            numberCounter *= 10;
        }
    }

    return digitLength; 
}

The way it works is with the number counter variable is that 10 = 1 digit space.它的工作方式是使用数字计数器变量是 10 = 1 位空间。 For example .1 = 1 tenth => 1 digit space.例如 .1 = 1 个十分位 => 1 位空格。 Therefore if you have int number = 103342;因此,如果您有int number = 103342; you'll get 6, because that's the equivalent of .000001 spaces back.你会得到 6,因为这相当于 0.000001 个空格。 Also, does anyone have a better variable name for numberCounter ?另外,有没有人有一个更好的numberCounter变量名? I can't think of anything better.我想不出更好的了。

Edit: Just thought of a better explanation.编辑:只是想到了一个更好的解释。 Essentially what this while loop is doing is making it so you divide your number by 10, until it's less than one.本质上,这个while循环所做的就是让你将你的数字除以10,直到它小于1。 Essentially, when you divide something by 10 you're moving it back one number space, so you simply divide it by 10 until you reach <1 for the amount of digits in your number.本质上,当您将某物除以 10 时,您会将其移回一个数字空间,因此您只需将其除以 10,直到您的数字中的位数达到 <1。

Here's another version that can count the amount of numbers in a decimal:这是另一个可以计算小数位数的版本:

public static int repeatingLength(double decimalNumber) {

    int numberCounter = 1;
    boolean condition = true;
    int digitLength = 1;

    while (condition) {
        double numberRatio = decimalNumber * numberCounter;

        if ((numberRatio - Math.round(numberRatio)) < 0.0000001) {
            condition = false;
        } else {
            digitLength++;
            numberCounter *= 10;
        }
    }
    return digitLength - 1;
}

是否有比此方法更整洁的方法来获取int中的位数?

int numDigits = String.valueOf(1000).length();

是否有比此方法更整洁的方法来获取int中的位数?

int numDigits = String.valueOf(1000).length();

是否有比此方法更整洁的方法来获取int中的位数?

int numDigits = String.valueOf(1000).length();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM