有没有比这个方法更简洁的方法来获取整数的位数?

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

当前回答

下面是JDK开发人员给出的解决方案。JDK 17 (Long类):

/**
 * Returns the string representation size for a given long value.
 *
 * @param x long value
 * @return string size
 *
 * @implNote There are other ways to compute this: e.g. binary search,
 * but values are biased heavily towards zero, and therefore linear search
 * wins. The iteration results are also routinely inlined in the generated
 * code after loop unrolling.
 */
static int stringSize(long x) {
    int d = 1;
    if (x >= 0) {
        d = 0;
        x = -x;
    }
    long p = -10;
    for (int i = 1; i < 19; i++) {
        if (x > p)
            return i + d;
        p = 10 * p;
    }
    return 19 + d;
}

注意,如果需要的话,该方法会考虑减号。

不幸的是,该方法没有公开。

在性能方面,您可以从评论中看到,JDK开发人员与其他选项相比至少考虑了这一点。我猜 分而治之的方法倾向于较小的数字,效果会稍好一些 更好,因为CPU可以比整数更快地进行整数比较 乘法。但这种差异可能小到无法测量。

无论如何,我希望JDK中已经公开了这个方法,这样人们就不会开始使用自己的方法了。

其他回答

这是我做的一个非常简单的方法,适用于任何数字:

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; 
}

它的工作方式是使用数字计数器变量,即10 = 1位空格。例如。1 = 1十分之一=> 1位空格。因此,如果你有int number = 103342;你会得到6,因为这相当于。000001个空格。还有,谁有更好的numberCounter变量名?我想不出比这更好的了。

编辑:我想到了一个更好的解释。本质上,这个while循环所做的就是让你的数字除以10,直到它小于1。从本质上讲,当你将一个数除以10时,你是在向后移动一个数字空间,所以你只需将它除以10,直到你的数字中的位数小于1。

下面是另一个版本,可以计算小数中的数字数量:

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;
}

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. 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. 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!

也就是说,上述两种方法在本例中都没有产生显著差异。

不管有没有这些修改,我得到的结果和你完全不同。当我运行这个时,是的,toString方法给出的运行时间为6400到6600 millis,而log方法给出的运行时间为20,000到20,400 millis。对数方法对我来说不是稍微快一点,而是慢了3倍。

请注意,这两种方法涉及非常不同的代价,所以这并不完全令人震惊:toString方法将创建许多必须清理的临时对象,而log方法需要更密集的计算。因此,可能区别在于,在内存较少的机器上,toString需要更多的垃圾收集回合,而在处理器较慢的机器上,额外的log计算将更加痛苦。

我还尝试了第三种方法。我写了这个小函数:

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;           
}

在我的机器上,它运行在1600到1900毫厘之间——不到toString方法的1/3,log方法的1/10。

如果您的数字范围很广,您可以通过开始除以1000或1,000,000来进一步加快速度,以减少循环的次数。我还没玩过。

使用Java

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

使用import java.lang.Math.*;一开始

使用C

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

在开始时使用include math.h

这个递归方法呢?

    private static int length = 0;

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

另一种字符串方法。简单明了,对于任意整数n。

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