int에서 자릿수를 얻는 방법?


385

이 방법보다 int의 길이를 얻는 더 좋은 방법이 있습니까?

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

7
int의 길이를 정의하십시오.
Tom

24
나는 그가 숫자의 숫자를 세고 싶다고 생각합니다.
Alberto Zaccagni

3
사람들이 당신에게주는 대답은 정확합니다 ... 문자열로 변환하지 않고 int 길이를 제공합니다 ...하지만 왜 문자열로 변환하고 싶지 않습니까? 속도인가? 그렇다면 이러한 방법이 더 빠를 것이라고 확신하지 못합니다. 몇 가지 테스트를 원하거나
중요한지

3
@ptomli 16 진 숫자는 여전히 다른 기본 시스템의 숫자입니다.
Mark Pim

2
@Ptomli는 물론 Integer.toString 함수와 일반 대화에서는 10 진수가 기본값입니다. 은행에서 "이 상자에 수표 금액을 쓰십시오"라고 말하면 10 진수, 16 진수 또는 8 진수로 써야하는지 묻지 않습니다. 문맥에 의해 달리 명시되거나 요구되지 않는 한 우리는 10 진수를 가정합니다.
Jay

답변:


349

문자열 기반 솔루션은 완벽하게 괜찮습니다. "정확하지 않은"것은 없습니다. 수학적으로 숫자는 길이가없고 숫자도 없다는 것을 알아야합니다. 길이와 숫자는 둘 다 특정 밑 (즉, 문자열)에서 숫자 의 물리적 표현 의 속성입니다 .

로그 기반 솔루션은 문자열 기반 솔루션과 내부적으로 동일한 작업을 수행하며 길이 만 생성하고 숫자를 무시하기 때문에 (중요하지 않게) 더 빠릅니다. 그러나 실제로 의도가 더 명확하다고 생각하지는 않습니다. 이것이 가장 중요한 요소입니다.


54
문제를 해결할 방법을 선택할 때 코드 의도를 고려하여 +1
pupeno

5
데이터 포인트 : 내 컴퓨터에서 로그 방법은 문자열 길이 방법보다 두 배 빠른 속도로 실행되는 것 같습니다. 메소드가 많이 호출되거나 시간이 중요한 코드 섹션에서 호출되는 경우에는 그다지 중요하지 않습니다.
CPerkins

1
아래의 벤치 마크 단위 테스트를 참조하십시오 (결함이있을 수 있습니다. 벤치 전문가가 아닙니다). 많은 수의 런 (100 000 000)에 걸쳐, 속도는 내 컴퓨터에서 거의 두 배나 빠르지 않습니다.
Jean

5
@CPerkins. 조기 최적화. 당신은 게임을 알고 있습니다.
Michael Borgwardt

11
일부 (꽤 늦음) 추가 : "-"가 숫자인지 여부에 따라 음수 값에 대해 제대로 작동하지 않을 수 있습니다. 추가하면 Math.abs()이 문제가 해결됩니다.
YingYang

265

로그는 당신의 친구입니다 :

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

NB : n> 0에만 유효합니다.


2
그리고 이것이 내 변형을 사용하는 것보다 빠르거나 낫습니까?
fnst

+1 당신은 1 초 만에 나를 때리고 당신의 대답은 옳았습니다. 그러나 int
Dirk

2
@Tom 왜 비싸다고 생각하십니까? 수학 코 프로세서가이를 실행한다고 가정 할 수 있으므로 추가 속도에 가까울 수 있습니다. Java가 현재 보조 프로세서를 사용하지 않더라도 다음과 같이 가정 할 수 있습니다. 당신이 있었다면 shootout.alioth.debian.org에 가서 스스로 알아보십시오)
Bill K

8
확인 ... 값이 0이 아닌 이상 작동하지 않으면 이상한 결과가 나타납니다 (-2147483647). Math.log10 API : "인수가 양의 0 또는 음의 0이면 결과는 음의 무한대입니다."
mujimu

2
+1 GC 수집을 피하기 위해 재사용을 최대화해야하는 객체 메모리 할당과 관련이없는 방법을 제시합니다.
Michael Wojcik

158

가장 빠른 방법 : 나누고 정복하십시오.

범위가 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 포함) : 2145ms
  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 방법 : 기준선의 711ms = 3.02 배
  3. 반복 분할 : 기준선보다 2797ms = 0.77 배
  4. 분할 정복 :
    기준선보다 74ms = 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 솔루션-반복 및 비교 : 406ms

광산은 Java 6 솔루션보다 약 4 배 빠릅니다.


7
이것은 좋아 보인다. ? : 연산자를 사용하여 좀 더 컴팩트하게 작성할 수 있습니다.
André Pareis

88
조기 최적화에 대해 이야기 : D
고든 구스타프손

2
나는 그것을 좋아한다! 이렇게 중첩 된 if-elsese 대신 스위치 블록은 어떻습니까?
Kebman

2
else 문이 int를 String으로 변환 한 다음 .length를 호출하는 것보다 훨씬 빠를 경우이 모든 것을 알지 못했습니다. +1
Ogen

15
삼항 연산자를 사용하여 101 자로 줄입니다.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
Jonathan Gawrych

13

벤치 마크에 대한 두 가지 의견 : Java는 복잡한 환경입니다 .Just-in-Time 컴파일 및 가비지 수집 등으로 벤치 마크를 실행할 때마다 공정한 비교를 얻으려면 항상 : (a) 두 테스트를 동봉하십시오. 루프를 순서대로 5 회 또는 10 회 실행합니다. 루프를 통한 두 번째 패스의 런타임은 첫 번째와 상당히 다릅니다. 그리고 (b) 각각의 "접근법"후에 System.gc ()를 수행하여 가비지 수집을 시작합니다. 그렇지 않으면, 첫 번째 접근 방식은 많은 오브젝트를 생성 할 수 있지만 가비지 콜렉션을 강제 실행하기에는 충분하지 않으며, 두 번째 접근 방식은 오브젝트를 생성하고 힙이 소진되며 가비지 콜렉션이 실행됩니다. 그런 다음 두 번째 방법은 첫 번째 방법으로 남은 쓰레기를 수거하기 위해 "충전"됩니다. 매우 불공평하다!

즉, 위의 어느 것도이 예에서 큰 차이를 만들지 않았습니다.

이러한 수정 여부에 관계없이 귀하와는 다른 결과를 얻었습니다. 내가 이것을 실행했을 때, 예, toString 접근 방식은 6400 ~ 6600 밀리미터의 실행 시간을 제공했지만 로그 접근 방식은 20,000 ~ 20,400 밀리미터를 차지했습니다. 약간 더 빠르지 않고 로그 접근 방식이 3 배 느 렸습니다.

두 접근 방식은 비용이 매우 다르므로 완전히 충격을주지는 않습니다. toString 접근 방식은 정리해야하는 많은 임시 객체를 생성하는 반면 로그 접근 방식은 더 많은 계산을 수행합니다. 따라서 메모리가 적은 컴퓨터에서는 toString에 더 많은 가비지 콜렉션 라운드가 필요하지만 프로세서가 느린 컴퓨터에서는 로그 계산이 더 어려워 질 수 있습니다.

또한 세 번째 접근법을 시도했습니다. 나는이 작은 기능을 썼다 :

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 미만이고 내 컴퓨터의 로그 접근 방식은 1/10입니다.

넓은 범위의 숫자가 있다면 1,000 또는 1,000,000으로 나누기 시작하여 루프를 통과하는 횟수를 줄임으로써 속도를 더 높일 수 있습니다. 나는 그와 함께 연주하지 않았습니다.


입력을 변경하려고 했습니까? 핫스팟 VM은 그렇지 않으면이 그래프를 최적화하여 매번 동일한 사전 계산 된 결과를 반환하므로 벤치 마크가 잘못 될 수 있습니다.
Erik Aigner

11

자바 사용하기

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초기에


1
FYI 만 있으면 the_integeris 0인 경우 무한대 가 되므로 확인하십시오.
Erik Aigner

9

아직 댓글을 남길 수 없으므로 별도의 답변으로 게시하겠습니다.

로그 기반 솔루션은 다음과 같이 매우 큰 정수에 대해 올바른 자릿수를 계산하지 않습니다.

long n = 99999999999999999L;

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

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

로그 기반 솔루션은 큰 정수로 잘못된 자릿수를 계산합니다.


대신 j가 10-(n-n / 10 * 10) 인 (int) (Math.log10 (n + j))를 사용해보십시오.
Erick Stone

8

정수의 밑이 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"도 특별한 경우라고 생각합니다.
DmitryK

예. 당신은 기호에 대한 계정이 필요한 경우, 당신은 같은 것을해야 할 것 (1) + (INT) Math.floor (Math.log10 (Math.abs (수))) + (? (수 <0) 1 : 0)
더크

5
Math.floor그것은 약간의 중복 그렇지? int어쨌든 반올림하여 캐스팅 합니다.
CompuChip

5

Marian의 솔루션은 누군가가 복사 및 붙여 넣기를 원할 경우 유형 번호 (최대 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으로 자릿수를 얻는 방법"으로 변경해야합니까? (및 'long'태그 추가)
JAIL

4

또 다른 문자열 접근 방식. 모든 정수에 대해 짧고 달콤합니다 n.

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

양의 정수 n와 0 에서만 작동 합니다. ("" + Math.abs(n)).length()음의 정수 길이를 얻는 데 사용할 수 있습니다 .
ThisClark

3

내가 해봐도 돼? ;)

더크 솔루션 기반

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

3

평범한 오래된 수학은 어떻습니까? 0이 될 때까지 10으로 나눕니다.

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

1
테스트 했습니까? 인간의 관점에서는 이해하기 힘들지만, 기계의 "생각"과 동일하게 작동하지는 않습니다. --- 한 가지를 제안하겠습니다. Long.MAX_VALUE코드의 최악의 복잡한 경우 인 200 만 개의 숫자 배열을 만들고 System.nanoTime()다른 솔루션의 최악의 복잡한 경우에 대해 클럭킹 시험을 수행하는 데 사용 하십시오. ++ 실제로, "평균 복잡성"테스트를 위해 무작위 범위를 0~로 설정 한 배열로 배열을 시도하십시오. Long.MAX_VALUE++ 결과는 매우 충격적입니다.
XenoRo

@thelima 이것은 제로 또는 네거티브에 대해 올바르게 작동하지 않지만 사소한 버그입니다. 원칙은 나에게 옳아 보인다. 무슨 "쇼킹"결과를 말하는거야?
Jay

컴퓨터가 ... 음 ... 분할을 좋아하지 않는다고 말합시다. 그리고 많은 수의 큰 "대기열"을 처리해야하고 각 처리 된 숫자의 각 숫자에 나눗셈이 필요한 경우 ... 음 ... 사물 "정말 느리게 시작합니다"... 의미 ... --- 여기에 테스트를 기반으로 한 코드를 사용하고 나누기보다는 'if'를 사용하여 각 소수 자릿수와 비교하는 코드를 사용하여 많은 답변을 볼 수있는 이유는 다음과 같습니다. 최악의 경우입니다. --- 큰 숫자에서 나누기와 로그를 사용하는 사이에 테스트를합니다 ...
XenoRo

@TheLima 무슨 소리 야? 들어 int,이 루프는 11 시간에서 최대를 행한다. 당신의 주장에 대한 증거가 있습니까?
Lorne의 후작

@EJP 하드웨어 관점에서 나누기는 반복 프로세스입니다. 내가 아는 가장 빠른 나눗셈 알고리즘은 radix4이며 반복 당 4 비트를 생성합니다. 따라서 32 비트 나누기는 8 회 이상 반복해야합니다. 예를 들어 곱셈은 병렬로 수행 될 수 있으며 더 간단한 곱셈으로 나눌 수 있습니다. 비트 수준으로 낮추거나 (5 개의 작업 만 필요함) 부분 분류와 끝에 룩업 테이블이 추가됩니다 (클래식 크기 VS 속도 절충). 단지 "얼마나 많은 반복"에 관한 것이 아닙니다. 분할의 문제는 "하드웨어 수준에서 각 반복이 암시 / 수행하는 것"
XenoRo

2

Ternary와 함께하는 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)));
    }

우리가 할 수 있기 때문에 .


2
읽기 어려워요. 공백이나 줄 바꿈을 추가하십시오.
michaelb958--GoFundMonica

하지만 젠장!
Trevor Rudolph

1

호기심, 나는 그것을 벤치 마크하려고했습니다 ...

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

이제 벤치 마크가 실제로 의미가 있는지 궁금해하지만 벤치 마크 자체의 여러 실행에 대해 일관된 결과 (ms 이내의 변화)를 얻습니다 ... :) 이것을 시도하고 최적화하는 것이 쓸모없는 것처럼 보입니다 ...


편집 : 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

1
그것의 재미를 위해서, 0에서 1 조에 이르는 숫자의 값 분포에 대한 차이점은 무엇입니까? :)
ptomli

0

이 재귀 방법은 어떻습니까?

    private static int length = 0;

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

0

간단한 해결책 :

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

0

정말 간단한 해결책 :

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

빈 본문이 간단한 루프의 한 줄을 호출하지 않습니다. 모듈로 10의 거듭 제곱으로 같은 결과를 얻었는지 확인하십시오 (비교를 사용할 수는 없습니까?).
Teepeemm

0

또는 길이가 원하는 숫자보다 크거나 작은 지 확인할 수 있습니다.

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

}


이해가 안 돼요 다른 질문에 답변 한 것 같습니다.
Teepeemm

0

아직 곱셈 기반 솔루션을 보지 못했습니다. 대수, 분할 및 문자열 기반 솔루션은 수백만 개의 테스트 사례에 비해 다루기 어려워 지므로 다음과 같은 사례가 있습니다 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와 비교되고 있기 때문에 작동합니다. 분은 9, 90, 900 ...이고 n은 9, 90, 900으로 빼기 때문입니다 ...

불행히도 이것은 오버플로로 인한 long모든 인스턴스를 교체 하는 것만으로 는 이식성이 없습니다 int. 다른 한편으로는 너무 그런 일 것이다 기지 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;
}

0

디자인 (문제에 따라). 이것은 분할 및 정복의 대안입니다. 우리는 먼저 열거 형을 정의 할 것입니다 (서명없는 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;
    }
}

이제 열거 형 값을 통과하는 클래스를 정의하고 적절한 길이를 비교하고 반환합니다.

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>=Nine.getValue()않습니까?
Teepeemm

0

어쨌든 명시 적으로 또는 암시 적으로 "toString-ed"(또는 다른 방식으로 변환)가되어야한다는 의미입니다. 제시되기 전에 (예를 들어 인쇄).

이 경우 필요한 "toString"을 명시 적으로 지정하고 비트 수를 계산하십시오.


0

재귀 루프를 사용하여이를 달성 할 수 있습니다

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

0

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

0

사람들이 String 라이브러리를 사용하거나 심지어 Integer 클래스를 사용하는 것을 보았습니다. 그것에 아무런 문제가 없지만 자릿수를 얻는 알고리즘은 그렇게 복잡하지 않습니다. 이 예제에서 long을 사용하고 있지만 int와 마찬가지로 잘 작동합니다.

 private static int getLength(long num) {

    int count = 1;

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

    return count;
}

0

String API, 유틸리티, 타입 변환, 순수 Java 반복 없음->

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

원한다면 더 큰 가치를 위해 오래 갈 수 있습니다.


-1
    int num = 02300;
    int count = 0;
    while(num>0){
         if(num == 0) break;
         num=num/10;
         count++;
    }
    System.out.println(count);

"10으로 나누기"솔루션은 2 년 전에 Sinista에 의해 처음 게시되었습니다.
Teepeemm

-1

쉬운 재귀 방법

int    get_int_lenght(current_lenght, value)
{
 if (value / 10 < 10)
    return (current_lenght + 1);
return (get_int_lenght(current_lenght + 1, value))
}

검증되지 않은


3
그런 다음 테스트해야합니다 (그리고 유효한 Java이고 올바른 형식인지 확인하십시오). 그러나 재귀 "10으로 나누기"접근법은 3 년 전에 Jedi Dula에 의해 게시되었습니다.
Teepeemm

-2

연속적인 나누기를 사용하여 숫자를 10으로 나눌 수 있습니다.

int a=0;

if (no < 0) {
    no = -no;
} else if (no == 0) {
    no = 1;
}

while (no > 0) {
    no = no / 10;
    a++;
}

System.out.println("Number of digits in given number is: "+a);

"10으로 나누기"접근법은 3 년 전 Sinista에 의해 처음 게시되었습니다. 그것이 내가 당신에게 공감대를 얻었다 고 생각할 수있는 유일한 이유입니다.
Teepeemm

-2

숫자를 입력하고을 생성 Arraylist하면 while 루프는 모든 숫자를에 기록합니다 Arraylist. 그런 다음 입력 한 정수 값의 길이가 될 배열의 크기를 가져올 수 있습니다.

ArrayList<Integer> a=new ArrayList<>();

while(number > 0) 
{ 
    remainder = num % 10; 
    a.add(remainder);
    number = number / 10; 
} 

int m=a.size();

1
ArrayList 또는 숫자가 필요하지 않은 것을 제외하고.
Lorne의 후작

-2

다음은 내가 만든 수많은 간단한 방법입니다.

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/10 => 1 자리 공간입니다. 따라서 int number = 103342;6을 얻으면 .000001 공백과 같습니다. 또한 누구나 더 나은 변수 이름을 가지고 numberCounter있습니까? 나는 더 나은 것을 생각할 수 없다.

편집 : 더 나은 설명을 생각했습니다. 본질적 으로이 while 루프가하는 일은 1보다 작을 때까지 숫자를 10으로 나누는 것입니다. 기본적으로 무언가를 10으로 나누면 하나의 숫자 공간으로 이동하므로 숫자의 자릿수가 <1에 도달 할 때까지 간단히 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;
}

-3

변환 시도 INT를 A와 문자열 다음의 길이를 얻을 문자열을 . 그것은 int 의 길이를 가져와야 합니다.

public static int intLength(int num){
    String n = Integer.toString(num);
    int newNum = n.length();
    return newNum;
}

이것은 원래 코드와 완전히 동일합니다. 그리고 number부정적인 경우 그리워 합니다.
Teepeemm
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.