【问题标题】:Way to get number of digits in an int?获取int中位数的方法?
【发布时间】:2010-11-21 08:38:36
【问题描述】:

有没有比这种方法更简洁的方法来获取 int 中的位数?

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

【问题讨论】:

  • 请定义一个int的长度。
  • 我想他是想数数。
  • 人们给你的答案是正确的......他们给你 int 的长度而不将它转换为字符串......但是你为什么不想将它转换为字符串?是速度问题吗?如果是这样,我不相信这些方法会更快......你可能想做一些测试(或决定它是否重要。)
  • @ptomli 十六进制数字仍然是数字,只是在不同的基本系统中。
  • @Ptomli 当然可以,但是在 Integer.toString 函数和一般对话中,十进制是默认值。当银行告诉我“把支票金额写在这个方框里”时,我不会问他们应该用十进制、十六进制还是八进制写。除非另有说明或上下文要求,否则我们假定为十进制。

标签: java integer


【解决方案1】:

对数是你的朋友:

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

注意:仅对 n > 0 有效。

【讨论】:

  • 这比使用我的变体更快还是更好?
  • +1 你比我快一秒,你的答案是对的,而我的答案稍有偏差。但请注意,编译器会因为缺少对 int 的强制转换而抱怨
  • @Tom 你为什么认为它很贵?有人可能会假设数学协处理器会执行它,所以它可能接近加法的速度。即使 java 现在不使用协处理器,它也是一个很好的假设,它可能......(我们将忽略你更未受过教育的暗示,即 Java 很慢,因为你可能对证据不感兴趣——或者如果你是你,你会去shootout.alioth.debian.org并自己找出来)
  • 有效...除非您检查的值 = 0,这会给您带来奇怪的结果 (-2147483647)。 Math.log10 API:“如果参数为正零或负零,则结果为负无穷大。”
  • +1 提出一种不涉及对象内存分配的方法,这是最大化重用以避免 GC 收集的必要条件。
【解决方案2】:

由于一个整数的基数为 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);
    }
}

已编辑,因为我上次的编辑修复了代码示例,但没有修复描述。

【讨论】:

  • 酷。但我认为它需要 abs(number) 并且“0”也是特例?
  • 是的。如果您需要考虑符号,则必须执行类似 1 + (int)Math.floor(Math.log10(Math.abs(number))) + ((number
  • Math.floor 有点多余,不是吗?投射到int 无论如何都会将其四舍五入。
  • @DmitryK @Dirk:注意Math.abs() 不适用于Integer.MIN_VALUE
【解决方案3】:

您的基于字符串的解决方案非常好,没有什么“不整洁”的地方。你必须意识到,在数学上,数字没有长度,也没有数字。长度和数字都是特定基数(即字符串)的物理表示的属性。

基于对数的解决方案(部分)执行与基于字符串的解决方案在内部执行的相同操作,并且可能执行速度更快(微不足道),因为它只产生长度并忽略数字。但我实际上并不认为它的意图更清晰 - 这是最重要的因素。

【讨论】:

  • +1 用于在选择解决问题的方法时考虑代码的意图
  • 数据点:在我的机器上,日志方法的运行速度似乎是字符串长度方法的两倍。如果该方法被大量调用或在代码的时间关键部分被调用,我不会认为这无关紧要。
  • 在下面查看我的基准单元测试(这也可能存在缺陷,我不是基准专家)。经过大量运行(100 000 000),我的机器上的速度是 11 秒到 8 秒,几乎没有两倍快。
  • @CPerkins。过早的优化。你懂的。
  • 一些(很晚的)补充:它可能不适用于负值,这取决于您是否希望“-”为数字。不过,添加 Math.abs() 将解决此问题。
【解决方案4】:

我可以试试吗? ;)

基于德克的解决方案

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

【讨论】:

  • 请注意Math.abs() 不适用于Integer.MIN_VALUE
【解决方案5】:

很好奇,我尝试对其进行基准测试...

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


    }
}

结果是:

运行时间1:6765 s: 400000000 运行时间2:6000 s: 400000000

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


编辑:根据 ptomli 的评论,我在上面的代码中将 'number' 替换为 'i' 并在 5 次运行中得到以下结果:

运行时间1:11500 s: 788888890 运行时间 2:8547 s: 788888890 运行时间1:11485 s: 788888890 运行时间 2:8547 s: 788888890 运行时间1:11469 s: 788888890 运行时间 2:8547 s: 788888890 运行时间1:11500 s: 788888890 运行时间 2:8547 s: 788888890 运行时间1:11484 s: 788888890 运行时间 2:8547 s: 788888890

【讨论】:

  • 只是为了好玩,从 0 到 1 万亿的数字值分布有什么区别? :)
【解决方案6】:

您的基准测试中的两个 cmets:Java 是一个复杂的环境,需要即时编译和垃圾收集等,因此为了公平比较,每当我运行基准测试时,我总是: (a) 附上这两个测试在一个循环中依次运行 5 或 10 次。很多时候,第二次循环的运行时间与第一次完全不同。并且 (b) 在每个“方法”之后,我都会执行 System.gc() 来尝试触发垃圾收集。否则,第一种方法可能会生成一堆对象,但不足以强制进行垃圾回收,然后第二种方法会创建一些对象,堆耗尽,然后垃圾回收运行。然后第二种方法是“收费”的,用于拾取第一种方法留下的垃圾。很不公平!

也就是说,在这个例子中,上述两种方法都没有显着差异。

无论有没有这些修改,我得到的结果都与你不同。当我运行它时,是的,toString 方法的运行时间为 6400 到 6600 毫秒,而 log 方法的运行时间为 20,000 到 20,400 毫秒。日志方法对我来说并没有稍微快一点,而是慢了 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。

如果您的数字范围很广,则可以先除以 1,000 或 1,000,000 以减少循环次数,从而进一步加快速度。我没玩过。

【讨论】:

  • 你试过改变输入吗?否则,热点 VM 可能会优化此图,从而导致错误的基准测试,因为它每次都返回相同的预计算内容。
  • 请注意Math.abs()不适用于Integer.MIN_VALUE,在这种情况下该方法将返回0。
【解决方案7】:

最快的方法:分而治之。

假设您的范围是 0 到 MAX_INT,那么您有 1 到 10 位数字。您可以使用分而治之的方法接近此间隔,每个输入最多进行 4 次比较。首先,通过一次比较将 [1..10] 划分为 [1..5] 和 [6..10],然后使用一次比较将每个长度为 5 的区间划分为一个长度为 3 的区间和一个长度为 2 的区间。长度为2的区间需要多比较一次(共3次比较),长度为3的区间可分为长度为1的区间(解)和长度为2的区间。因此,您需要进行 3 或 4 次比较。

没有除法,没有浮点运算,没有昂贵的对数,只有整数比较。

代码(长但快):

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

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

  1. 基线方法(使用 String.length): 2145 毫秒
  2. log10 方法:711ms = 3.02 次 与基线一样快
  3. 重复除法:2797ms = 0.77 次 与基线一样快
  4. 分而治之:74ms = 28.99
    比基线快几倍

完整代码:

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

再次,基准测试:

  1. 基线方法(使用String.length):2145ms
  2. log10 方法:711 毫秒 = 是基线的 3.02 倍
  3. 重复除法:2797 毫秒 = 比基线快 0.77 倍
  4. 分而治之:74 毫秒 = 比基线快 28.99 倍

编辑

在编写基准测试后,我从 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;
}

我将它与我的分而治之解决方案进行了基准测试:

  1. 分而治之:104ms
  2. Java 6 解决方案 - 迭代和比较:406 毫秒

我的速度大约是 Java 6 解决方案的 4 倍。

【讨论】:

  • 这看起来很棒。您可以使用 ?: 运算符将其写得更紧凑,以获得更多接受度
  • 谈论过早优化:D
  • 我喜欢!用 switch 块代替嵌套的 if-elseses 怎么样?
  • 我没有意识到所有这些 if else 语句会比将 int 转换为 String 然后调用 .length 快得多。 +1
  • 使用三元运算符,将其减少到 101 个字符:n&lt;100000?n&lt;100?n&lt;10?1:2:n&lt;1000?3:n&lt;10000?4:5:n&lt;10000000?n&lt;1000000?6:7:n&lt;100000000?8:n&lt;1000000000?9:10
【解决方案8】:

Marian 的解决方案适用于 long 类型的数字(最多 9,223,372,036,854,775,807),以防有人想要复制和粘贴它。 在我编写的程序中,高达 10000 的数字更有可能,所以我为它们做了一个特定的分支。无论如何,它不会产生重大影响。

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

【讨论】:

  • 这个问题的标题是否应该改为“获取 int/long 中位数的方法?” (并添加了“长”标签)
【解决方案9】:

简单的旧数学怎么样?除以 10 直到 0。

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

【讨论】:

  • 你测试了吗?你知道,即使它对人类的观点来说是有意义的,但它与机器的“思维方式”并不完全一样,对吧? --- 让我提出一件事:制作一个包含 200 万个数字的数组,最好是 Long.MAX_VALUE,这是您的代码最复杂的情​​况,并使用 System.nanoTime() 对其他解决方案的最复杂的情​​况进行计时试验。 ++实际上,尝试使用由设置为0Long.MAX_VALUEtoo 范围的随机器填充的数组,只是为了“平均复杂度”测试++ 你可能会发现结果......非常令人震惊。
  • @thelima 这对于零或负数不能正常工作,但这是一个小错误。这个原则在我看来是正确的。你指的是什么“令人震惊”的结果?
  • 假设计算机...嗯...它们不喜欢分割。在需要处理大量“队列”的情况下,每个处理后的数字中的每个数字都需要一个除法......嗯......事情“开始变得非常慢非常快”......如果你抓住我的意思... ---这就是为什么您在这里看到许多答案的原因是使用基于测试的代码并使用“if”而不是除法与每个十进制数字进行比较:如果它不快,至少它保持了大部分的速度不管这是最坏的情况。 --- 在大数上使用除法和对数进行测试...
  • @TheLima 你在说什么?对于int,,此循环最多执行 11 次。你的论断有证据吗?
  • @EJP 从硬件的角度来看,除法是一个迭代过程。我所知道的最快的除法算法是 radix4,每次迭代产生 4 位;所以 32 位除法至少需要 8 次迭代。例如,乘法可以并行进行,也可以分解为更简单的乘法;要么下降到位级别(仅需要 5 次操作),要么部分分解加上最后的查找表(经典大小与速度权衡)。这不仅仅是关于“多少次迭代”;划分的问题在于“在硬件级别上,每次迭代意味着/做什么”
【解决方案10】:

这个递归方法怎么样?

    private static int length = 0;

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

【讨论】:

    【解决方案11】:

    简单的解决方案:

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

    【讨论】:

      【解决方案12】:

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

      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,因为这相当于 0.000001 个空格。另外,有没有人为numberCounter 提供更好的变量名?我想不出更好的了。

      编辑:只是想到了一个更好的解释。本质上,这个while循环所做的就是让你将你的数字除以10,直到它小于1。本质上,当您将某物除以 10 时,您会将其移回一个数字空间,因此您只需将其除以 10,直到您的数字中的位数达到

      这是另一个可以计算小数位数的版本:

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

      【讨论】:

        【解决方案13】:

        Marian 的解决方案,现在使用三元:

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

        因为我们可以。

        【讨论】:

        • 这有点难读。也许添加一些空格和/或换行符。
        • 但该死的它是便携的!
        【解决方案14】:

        一个非常简单的解决方案:

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

        【讨论】:

        • 我不会用简单的空体调用单行 for 循环。也不以 10 的幂为模,看看你是否得到同样的东西(你不能只使用比较吗?)。
        【解决方案15】:

        有设计(基于问题)。这是分而治之的替代方案。我们将首先定义一个枚举(考虑到它仅适用于无符号整数)。

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

        现在我们将定义一个类,该类遍历枚举值并比较并返回适当的长度。

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

        此解决方案的运行时间与分治法相同。

        【讨论】:

        • 分而治之将从中间开始并将剩余的搜索区域一分为二。这具有线性运行时间。但这仅对 9 次比较无关紧要。但是如果num&gt;=Nine.getValue(),这不会搞砸吗?
        【解决方案16】:

        或者您可以检查数字是否大于或小于所需数字的长度。

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

        }

        【讨论】:

        • 我不明白。您似乎在回答另一个问题。
        【解决方案17】:

        我还没有看到基于乘法的解决方案。对于数百万个测试用例,对数、除法和基于字符串的解决方案将变得相当笨拙,所以这是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;
        }
        

        以 10 为底,这是有效的,因为 n 本质上是与 9、99、999... 进行比较的,因为 min 是 9、90、900...,而 n 被 9、90、900...减去/p>

        不幸的是,由于溢出,仅通过替换 int 的每个实例,这不能移植到 long。另一方面,它恰好适用于基数 2 和 10(但对于大多数其他基数来说严重失败)。您需要一个查找表来查找溢出点(或除法测试...... 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;
        }
        

        【讨论】:

          【解决方案18】:

          还不能发表评论,所以我将作为单独的答案发布。

          基于对数的解决方案不会为非常大的长整数计算正确的位数,例如:

          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

          【讨论】:

          • 尝试 (int) (Math.log10(n+j)) 代替 j 为 10 - (n - n/10*10)。
          【解决方案19】:

          我们可以使用递归循环来实现这一点

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

          【讨论】:

            【解决方案20】:

            一个人想要这样做主要是因为他/她想要“呈现”它,这主要意味着它最终需要显式或隐式地“toString-ed”(或以另一种方式转换);在展示之前(例如打印)。

            如果是这种情况,那么只需尝试明确必要的“toString”并计算位数。

            【讨论】:

              【解决方案21】:

              使用 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;
              

              在开头使用inclue math.h

              【讨论】:

              • 仅供参考,如果the_integer0 将导致无穷大,因此请检查。
              • 请注意Math.abs() 不适用于Integer.MIN_VALUE
              • 为什么要铺地板?我认为没有必要,你能解释一下吗?即使是 +1 是获得实际数字计数所需的,我认为地板是不必要的。
              【解决方案22】:

              另一种字符串方法。简短而甜蜜 - 适用于任何整数 n

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

              【讨论】:

              • 仅适用于正整数n 和零。可以使用("" + Math.abs(n)).length()获取负整数的长度。
              • 请注意Math.abs() 不适用于Integer.MIN_VALUE
              【解决方案23】:

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

              【讨论】:

                【解决方案24】:

                我看到人们使用 String 库,甚至使用 Integer 类。这没有错,但获取位数的算法并不复杂。我在这个例子中使用了 long 但它与 int 一样好。

                 private static int getLength(long num) {
                
                    int count = 1;
                
                    while (num >= 10) {
                        num = num / 10;
                        count++;
                    }
                
                    return count;
                }
                

                【讨论】:

                  【解决方案25】:

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

                  如果愿意,您可以长期追求更大的价值。

                  【讨论】:

                  • 这将对所有大于 1874919423 的值无限循环。要了解原因,请尝试以下操作:for (int x = 1, i = 0; i &lt; 32; ++i) { System.out.println(x *= 10); }
                  【解决方案26】:

                  计算int 变量中位数的一种有效方法是定义一个方法digitsCounter,其中包含所需数量的条件语句。
                  方法很简单,我们将检查 n 数字可能位于的每个范围:
                  0 : 9Single 数字
                  10: 99Double 数字
                  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;
                      }
                  

                  执行此操作的更简洁的方法是取消对下限的检查,因为如果我们以顺序方式进行,则不需要它。

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

                  【讨论】:

                    猜你喜欢
                    • 2012-06-24
                    • 2018-08-31
                    • 1970-01-01
                    • 2019-06-05
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-04-04
                    • 1970-01-01
                    • 2018-11-19
                    相关资源
                    最近更新 更多