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

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中已经公开了这个方法,这样人们就不会开始使用自己的方法了。

其他回答

那简单的数学呢?除以10,直到0。

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

理想情况下,一个整数除以10的倍数将返回位数,只要该整数不为零。这样一个简单的方法可以创建如下所示。

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

出于好奇,我试着对其进行基准测试……

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


    }
}

结果如下:

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

现在我想知道我的基准测试是否真的意味着什么,但我确实在基准测试本身的多次运行中得到了一致的结果(一毫秒内的变化)……:)看起来这是无用的尝试和优化…


编辑:根据ptomli的注释,我在上面的代码中用' I '替换'number',并在5次运行的bench中得到以下结果:

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

或者相反,你可以检查这个数字是否大于或小于所需的数字。

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

}

我看到有人使用String库,甚至使用Integer类。这没什么问题,但是求位数的算法并不复杂。我在这个例子中使用的是long类型,但它也可以用于int类型。

 private static int getLength(long num) {

    int count = 1;

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

    return count;
}