Number of Digits in an Integer in Java – Java中整数的位数

最后修改: 2017年 9月 10日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In this quick tutorial, we’ll explore different ways of getting the number of digits in an Integer in Java.

在这个快速教程中,我们将探讨在Java中获取Integer中数字的不同方法。

We’ll also analyze the different methods to figure out which algorithm would best fit each situation.

我们还将分析不同的方法,以弄清哪种算法最适合每种情况。

2. Number of Digits in an Integer

2.一个整数中的数字

For the methods discussed here, we’re only considering positive integers. If we expect any negative input, then we can first make use of Math.abs(number) before using any of these methods.

对于这里讨论的方法,我们只考虑正整数。如果我们期待任何负数的输入,那么我们可以在使用这些方法之前首先使用Math.abs(number)

2.1. String-Based Solution

2.1.基于字符串的解决方案

Perhaps the easiest way of getting the number of digits in an Integer is by converting it to String, and calling the length() method. This will return the length of the String representation of our number:

也许获取Integer中的数字的最简单方法是将其转换为String,并调用length()方法。这将返回我们的数字的String表示的长度。

int length = String.valueOf(number).length();

However, this may be a sub-optimal approach, as this statement involves memory allocation for a String for each evaluation. The JVM must parse our number and copy its digits into a separate String, as well as perform a number of other different operations (like keeping temporary copies, handle Unicode conversions, etc).

然而,这可能是一种次优的方法,因为该语句涉及为每次评估的String 分配内存。JVM必须解析我们的数字,并将其数字复制到一个单独的String中,以及执行其他一些不同的操作(如保持临时副本,处理Unicode转换等)。

If we only have a few numbers to evaluate, then we can use this solution because the difference between this and any other approach will be negligible, even for large numbers.

如果我们只有几个数字需要评估,那么我们可以使用这种解决方案,因为这和其他任何方法之间的差异将可以忽略不计,即使是大数字。

2.2. Logarithmic Approach

2.2.对数法

For numbers represented in decimal form, if we take their log in base 10 and round it up, we’ll get the number of digits in that number:

对于以小数形式表示的数字,如果我们以10为基数取其对数,并将其四舍五入,我们将得到该数字的数字数。

int length = (int) (Math.log10(number) + 1);

Note that log100 of any number isn’t defined, so if we’re expecting any input with value 0, then we can put a check for that as well.

请注意,任何数字的log100都没有被定义,所以如果我们期待任何数值为0的输入,那么我们也可以为之设置一个检查。

The logarithmic approach is significantly faster than the String based approach, as it doesn’t have to go through the process of any data conversion. It just involves a simple, straightforward calculation without any extra object initialization or loops.

对数方法明显比基于String的方法更快,因为它不需要经过任何数据转换的过程。它只是涉及一个简单、直接的计算,没有任何额外的对象初始化或循环。

2.3. Repeated Multiplication

2.3.重复的乘法

In this method, we’ll take a temporary variable (initialized to 1) and continuously multiply it by 10 until it becomes greater than our number. During this process, we’ll also use a length variable, which will keep track of the number’s length:

在这个方法中,我们将使用一个临时变量(初始化为1)并不断地将其乘以10,直到它大于我们的数字。在这个过程中,我们还将使用一个length变量,它将跟踪数字的长度。

int length = 0;
long temp = 1;
while (temp <= number) {
    length++;
    temp *= 10;
}
return length;

In this code, temp *= 10 is the same as writing temp = (temp << 3) + (temp << 1). Since multiplication is usually a costlier operation on some processors compared to shift operators, the latter may be a bit more efficient.

在这段代码中,temp *= 10与写temp = (temp << 3) + (temp << 1)相同。由于与移位运算符相比,乘法运算在某些处理器上通常是成本较高的运算,因此后者的效率可能更高一些。

2.4. Dividing With Powers of Two

2.4.用二的幂数除法

If we know the range of our number, then we can use a variation that will further reduce our comparisons. This method divides the number by powers of two (e.g. 1, 2, 4, 8, etc.):

如果我们知道我们的数字的范围,那么我们可以使用一种变通方法,进一步减少我们的比较。这种方法是将数字除以2的幂(例如:1、2、4、8等)。

int length = 1;
if (number >= 100000000) {
    length += 8;
    number /= 100000000;
}
if (number >= 10000) {
    length += 4;
    number /= 10000;
}
if (number >= 100) {
    length += 2;
    number /= 100;
}
if (number >= 10) {
    length += 1;
}
return length;

It takes advantage of the fact that any number can be represented by the addition of powers of 2. For example, 15 can be represented as 8+4+2+1, which are all powers of 2.

例如,15可以表示为8+4+2+1,它们都是2的幂。

For a 15 digit number, we would be doing 15 comparisons in our previous approach, compared to just four in this method.

对于一个15位数的数字,我们在以前的方法中要进行15次比较,而在这个方法中只需要4次。

2.5. Divide and Conquer

2.5 分裂与征服

This is perhaps the bulkiest approach when compared to all the others described here; however, it’s also the fastest because we’re not performing any type of conversion, multiplication, addition, or object initialization.

与这里描述的所有其他方法相比,这也许是最庞大的方法;然而,它也是最快的,因为我们没有执行任何类型的转换、乘法、加法或对象初始化。

We can get our answer in just three or four simple if statements:

我们只需用三或四个简单的if语句就可以得到答案。

if (number < 100000) {
    if (number < 100) {
        if (number < 10) {
            return 1;
        } else {
            return 2;
        }
    } else {
        if (number < 1000) {
            return 3;
        } else {
            if (number < 10000) {
                return 4;
            } else {
                return 5;
            }
        }
    }
} else {
    if (number < 10000000) {
        if (number < 1000000) {
            return 6;
        } else {
            return 7;
        }
    } else {
        if (number < 100000000) {
            return 8;
        } else {
            if (number < 1000000000) {
                return 9;
            } else {
                return 10;
            }
        }
    }
}

Similar to the previous approach, we can only use this method if we know the range of our number.

与前面的方法类似,我们只有在知道我们的数字范围的情况下才能使用这种方法。

3. Benchmarking

3.标杆管理

Now that we have a good understanding of the potential solutions, let’s do some simple benchmarking of our methods using the Java Microbenchmark Harness (JMH).

现在我们对潜在的解决方案有了充分的了解,让我们使用Java Microbenchmark Harness(JMH)对我们的方法做一些简单的基准测试。

The following table shows the average processing time of each operation (in nanoseconds):

下表显示了每个操作的平均处理时间(单位:纳秒)。

Benchmark                            Mode  Cnt   Score   Error  Units
Benchmarking.stringBasedSolution     avgt  200  32.736 ± 0.589  ns/op
Benchmarking.logarithmicApproach     avgt  200  26.123 ± 0.064  ns/op
Benchmarking.repeatedMultiplication  avgt  200   7.494 ± 0.207  ns/op
Benchmarking.dividingWithPowersOf2   avgt  200   1.264 ± 0.030  ns/op
Benchmarking.divideAndConquer        avgt  200   0.956 ± 0.011  ns/op

The String-based solution, which is the simplest, is also the most costly operation, as it’s the only one which requires data conversion and the initialization of new objects.

基于String的解决方案是最简单的,也是成本最高的操作,因为它是唯一需要数据转换和初始化新对象的方案。

The logarithmic approach is significantly more efficient than the previous solution, as it doesn’t involve any data conversion. Also, being a single line solution, it can be a good alternative to the String-based approach.

对数方法明显比之前的解决方案更有效率,因为它不涉及任何数据转换。此外,作为一个单行解决方案,它可以成为基于String-的方法的良好替代。

Repeated multiplication involves simple multiplication in proportion with the number length; for example, if a number is 15 digits long, then this method will involve 15 multiplications.

重复乘法涉及与数字长度成比例的简单乘法;例如,如果一个数字有15位,那么这种方法将涉及15次乘法。

However, the very next method takes advantage of the fact that every number can be represented by powers of two (the approach similar to BCD). It reduces the same equation to four division operations, so it’s even more efficient than the former.

然而,接下来的方法利用了每个数字都可以用2的幂来表示的事实(类似于BCD的方法)。它将同样的方程简化为四次除法运算,所以它比前者更有效率。

Finally, as we can infer, the most efficient algorithm is the verbose Divide and Conquer implementation, which delivers the answer in just three or four simple if statements. We can use it if we have a large dataset of numbers we need to analyze.

最后,正如我们可以推断的那样,最有效的算法是冗长的 “除法与征服 “实现,它只用三或四个简单的if语句就能给出答案。如果我们有一个需要分析的大型数字数据集,我们可以使用它。

4. Conclusion

4.结论

In this brief article, we outlined some of the ways to find the number of digits in an Integer, and compared the efficiency of each approach.

在这篇简短的文章中,我们概述了一些寻找整数中的数字的方法,并比较了每种方法的效率。

As always, the complete code is available over on GitHub.

一如既往,完整的代码可在GitHub上获得