정수로 자릿수를 결정하는 효율적인 방법


144

C ++에서 정수에 몇 자릿수가 있는지 결정하는 가장 효율적인 방법은 무엇입니까 ?


11
어떤 기지에서? 2? 10?
Jacob Krall

2
나는 기초 10에서 그것을하고 싶습니다
Seth

1
나는 한 번 관련 질문을했다 : int에서 첫 번째 숫자를 어떻게 얻을 수 있습니까? 아래에서와 같은 많은 방법론이 사람들의 답변에 사용되었습니다. 귀하의 작업과 관련이있는 경우를위한 링크는 다음과 같습니다 [ stackoverflow.com/questions/701322/]
Dinah

인라인 어셈블리 자격이 있습니까?
György Andrasek

1
이 모든 대답은 밑이 10 인 반면, 원하는 밑의 결과를 계산하도록 변경하는 것은 매우 쉽습니다.
Ira Baxter

답변:


106

음, 정수의 크기를 알고 있다고 가정하면 가장 효율적인 방법은 조회입니다. 훨씬 짧은 대수 기반 접근 방식보다 빠릅니다. '-'계산에 신경 쓰지 않으면 + 1을 제거하십시오.

// generic solution
template <class T>
int numDigits(T number)
{
    int digits = 0;
    if (number < 0) digits = 1; // remove this line if '-' counts as a digit
    while (number) {
        number /= 10;
        digits++;
    }
    return digits;
}

// partial specialization optimization for 32-bit numbers
template<>
int numDigits(int32_t x)
{
    if (x == MIN_INT) return 10 + 1;
    if (x < 0) return numDigits(-x) + 1;

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

// partial-specialization optimization for 8-bit numbers
template <>
int numDigits(char n)
{
    // if you have the time, replace this with a static initialization to avoid
    // the initial overhead & unnecessary branch
    static char x[256] = {0};
    if (x[0] == 0) {
        for (char c = 1; c != 0; c++)
            x[c] = numDigits((int32_t)c);
        x[0] = 1;
    }
    return x[n];
}

5
아마 내 대답보다 빠를 것입니다. 효율성을 높이기 위해 입력 숫자가 대부분 작은 숫자라는 것을 알고 있다면 (10 만 미만으로 추측) 테스트를 취소하십시오. if (x <10) return 1; (x <100) 2를 반환하면; 기능을 사용하면 테스트 횟수가 줄어들고 더 빨리 종료됩니다.
squelart

29
또는 선형 검색 대신 이진 검색을 수행하기 위해 if 문을 재정렬하고 중첩시킬 수 있습니다.
dave4420

1
그건 좋은 생각이 아니다. 아키텍처가 256 비트 정수로 확장되면 어떻게됩니까? 돌아와서이 코드를 수정해야합니다. 실제로 일어나지 않을 실제 생활에서 이것은 아마도 올바른 크기의 버퍼를 만드는 데 사용될 것입니다. 이제 더 큰 아키텍트에서 실행 문제에 대한 모든 종류의 버퍼를 열 수 있습니다.
마틴 요크

3
숫자가 균일하게 분포되어 있다고 가정하면 역 선형 검색 (최대 자릿수에서 1로 시작)은 N-1 자릿수보다 N 자릿수가있는 숫자가 상당히 많기 때문에 이진 검색보다 평균적으로 더 빠를 수 있습니다. graphics.stanford.edu/~ seander /…
fa.

6
256 또는 128 비트 정수에 대해서는 크게 걱정하지 않습니다. 당신이 우주에서 전자의 수를 계산할 필요가 없다면 (마지막으로 10 ^ 78 번), 64 비트는 꽤 잘 할 것입니다. 32 비트 머신은 ~~ 15 년 지속되었습니다. 나는 64 비트 머신이 훨씬 오래 지속될 것이라고 생각합니다. 숫자가 클수록 다중 정밀도 산술이 좋을 것이고 계산 자리 수의 효율성이 중요한지 의심 스럽습니다.
Ira Baxter

74

가장 간단한 방법은 다음과 같습니다.

unsigned GetNumberOfDigits (unsigned i)
{
    return i > 0 ? (int) log10 ((double) i) + 1 : 1;
}

log10은 다음에서 정의됩니다. <cmath> 또는에<math.h> 있습니다. 여기에 게시 된 다른 것보다 빠른지 확인하려면이 프로파일을 작성해야합니다. 부동 소수점 정밀도와 관련하여 이것이 얼마나 강력한 지 잘 모르겠습니다. 또한 인수는 음수 값으로 부호가 없으며 로그는 실제로 혼합되지 않습니다.


7
32 비트 정수 및 56 비트 부동 소수점의 경우 아마도 작동합니다. 입력이 긴 (64 비트) 경우 56 비트의 배정 밀도 로그는 10 ^ n의 큰 값에 가까운 값의 경우 잘못된 응답을 생성 할 수 있습니다. 2 ^ 50 이상에서는 문제가 발생할 수 있습니다.
Ira Baxter

1
로그 기능의 정확성에 대한 질문도 있습니다. 나는 그들이 현대 도서관에서 얼마나 정확한지 점검하지 않았으며, 10 억 분의 1이 좋다는 것을 맹목적으로 믿지 않는 것이 불편하다.
David Thornley

@DavidThornley : 컴파일러 명령 줄에 지정되지 않은 경우 로그 또는 기타 수학 함수는 완벽합니다. 일부는 컴파일 타임에 x86 내장 함수로 변환됩니다. 일부는 존재하지 않으며 기존 내장 함수의 공식으로 확장됩니다. 예를 들어 -fpfastx87 대신 SSE instrinsics를 사용하면 정밀도 IIRC에 대한 보증이 줄어 듭니다. 그러나 기본적으로 아무런 문제가 없습니다.
v.oddou

@DavidThornley : 정밀도 이상의 것입니다. 문제는 모든 관련 k에 대해 log10 (10 ^ k) ≥ k가 보장되는지 여부입니다. 즉, 불가피한 반올림 오류는 올바른 방향으로 진행됩니다. k + eps는 결과로 작동하지만 k-eps는 작동하지 않습니다. 그리고 "완벽하게 정밀하다"는 순진합니다.
gnasher729

1
i> 0 테스트는 i> 9에 최적화 될 수 있습니다
Pat

60

아마도 나는 그 질문을 잘못 이해했지만 그렇지 않습니까?

int NumDigits(int x)  
{  
    x = abs(x);  
    return (x < 10 ? 1 :   
        (x < 100 ? 2 :   
        (x < 1000 ? 3 :   
        (x < 10000 ? 4 :   
        (x < 100000 ? 5 :   
        (x < 1000000 ? 6 :   
        (x < 10000000 ? 7 :  
        (x < 100000000 ? 8 :  
        (x < 1000000000 ? 9 :  
        10)))))))));  
}  

29
그리고이 솔루션이 가장 빠를지라도 놀라지 않을 것입니다.
VisioN

32
int digits = 0; while (number != 0) { number /= 10; digits++; }

참고 : "0"은 0 자리입니다. 1 자리 숫자가 0으로 나타나려면 다음을 사용하십시오.

int digits = 0; do { number /= 10; digits++; } while (number != 0);

(감사합니다. Kevin Fegan)

결국, 프로파일 러를 사용하여 여기에있는 모든 답변 중 어느 것이 컴퓨터에서 더 빠를 지 알 수 있습니다 ...


3
이것은 내가 가져온 언롤 루프 접근법보다 빠르거나 빠를 수 있습니다. 차이를 프로파일 링해야합니다 (장기적으로 무시할 수 있음).
Vitali

동의, 프로파일 링은 정말로 확실하게 알 수있는 유일한 방법입니다! Ben S의 ceil (log10 ()) 답변이 사라지면서 답변을 해당 의견으로 업데이트했습니다.
squelart

11

실제 농담이있다 가장 효율적인 방법은 (자릿수는 컴파일 시간에 계산됩니다)

template <unsigned long long N, size_t base=10>
struct numberlength
{
    enum { value = 1 + numberlength<N/base, base>::value };
};

template <size_t base>
struct numberlength<0, base>
{
    enum { value = 0 };
};

서식, 입력 요소 등에서 숫자 필드에 필요한 너비를 결정하는 데 유용 할 수 있습니다.


4
첫째, 귀하의 솔루션은 0으로 작동하지 않습니다. 둘째, 귀하의 솔루션은 변수의 일반적인 경우에는 적용 할 수 없습니다. 셋째, 상수 리터럴을 사용하는 경우 이미 보유한 자릿수를 알고 있습니다.
Vitali

0에도 작동합니다. 또한 모든 기반에서 작동합니다. 나머지는 내가 이미 설명한 유효한 포인트입니다.
blinnov.com

3
나는 실제로 그렇게 생각하지 않습니다. 그것은에 실패 0하며 기본에 실패 1:)과베이스는 다음과 같이 주어지면 제로 오류에 의해 분할을 제공합니다 0. 그래도 고칠 수 있습니다. 어쨌든 나는 아주 오래된 게시물을 nitpicking하고 있습니다. 죄송합니다. 이것이 농담 일 필요는 없으며 실제로 유용 할 수 있다고 생각합니다.
tjm

9

수락 한 답변의 훨씬 짧은 버전은 Bit Twiddling Hacks 를 참조하십시오 . 또한 큰 상수를 먼저 확인하여 입력이 정상적으로 분포되면 답변을 더 빨리 찾을 수 있다는 이점이 있습니다. (v >= 1000000000)값의 76 %를 포착하므로 평균적으로 먼저 확인하는 것이 더 빠릅니다.


비트 비틀 링이 실제로 더 빠른지 확실하지 않습니다. 최악의 경우에도 수정 된 접근법에는 4 가지 비교가 필요합니다 (파티션을 더 자세히 살펴보면 3으로 줄일 수 있습니다). 나는 산술 연산 + 메모리로드 (충분히 액세스하면 CPU 캐시에서 사라짐)에 의해 이길 것이라고 의심합니다. 그들이 제공하는 예에서, 그들은 또한 추상적 인 IntegerLogBase2 함수 (실제로는 저렴하지는 않음)로서 로그베이스 2를 숨 깁니다.
Vitali

후속 조치와 마찬가지로 숫자가 정상적으로 분포되어 있으면 순서대로 검사하는 것이 더 빠릅니다. 그러나 최악의 경우 성능이 두 배 느리게 저하됩니다. 입력 공간 대신 ​​자릿수로 분할 된 접근 방식은 동작이 저하되지 않고 항상 최적으로 수행됨을 의미합니다. 또한 숫자가 균일하게 분포된다는 가정을하고 있음을 기억하십시오. 실제로 <a href=" en.wikipedia.org/wiki/…> 와 관련된 일부 배포판을 따르는 경향 이 있습니다.
Vitali

비트 트위들 링 해킹은 위의 파티션 방법보다 빠르지 않지만 여기에 플로트와 같은보다 일반적인 경우가 있다면 잠재적으로 흥미 롭습니다.
Corwin Joy

1
비트 트위들 링 해킹은 int log2가 주어지면 int log10을 얻는 방법을 제안합니다. int log2를 얻는 몇 가지 방법을 제안합니다. 대부분 비교 / 분기가 거의 없습니다. (비탈리 예측할 수없는 지점의 비용을 과소 평가한다고 생각합니다). 인라인 x86 asm을 사용할 수있는 경우 BSR 명령어는 int log2 값을 제공합니다 (즉, 가장 중요한 세트 비트의 비트 인덱스). K8 (10주기 대기 시간)에서는 약간 느리지 만 코어 2 (2 또는 3주기 대기 시간)에서는 빠릅니다. K8에서도 비교보다 빠를 수 있습니다.
Peter Cordes

K10에서 lzcnt는 선행 0을 계산하므로 bsr과 거의 동일하지만 0의 입력은 더 이상 정의되지 않은 결과가있는 특별한 경우가 아닙니다. 대기 시간 : BSR : 4, LZCNT : 2.
Peter Cordes

8

문자열로 변환 한 후 내장 함수 사용

unsigned int i;
cout<< to_string(i).length()<<endl;

7
int x = 1000;
int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;

3
이것은 LOC 측면에서 효율적이지만 허용되는 로그 사용에 언급 된 것처럼 최상의 성능을 제공하지 못할 수 있습니다.
Ian

@Ian 왜 안돼? FPU 명령어는 두 개뿐입니다. 모든 지점보다 더 나은 마일과 다른 답변을 반복합니다.
에 Lorne

5

이전 포스터는 10으로 나누는 루프를 제안했습니다. 최신 컴퓨터에서는 곱하기가 훨씬 빠르므로 대신 다음 코드를 사용하는 것이 좋습니다.

 int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }

1
악마는 세부 사항에 있습니다
-std

2
이 경우가 걱정되면 IF를 하나 더 추가하여 매우 큰 값을 처리 할 수 ​​있습니다.
Ira Baxter

2
x86 머신에서이 경우에 사용 된 상수 10을 곱하면 LEA R2, [8 * R1 + R1], ADD R1, R2와 같이 컴파일러에 의해 실제로 구현 될 수 있으므로 최대 2 클럭이 걸린다는 것을 알아야합니다. 변수에 곱하면 수십 개의 시계가 걸리고 나누기가 훨씬 더 나쁩니다.
Ira Baxter

나누기 접근법의 장점은 음수에 대해 걱정할 필요가 없다는 것입니다.
Johannes Schaub-litb

1
나는 multipication 접근법 (기호 문제를 제거하기위한 팹)과 벤치 마크 접근법을 벤치마킹했다. 내 기계에서 나눗셈 방식은 곱셈 방식보다 요소 2가 느립니다. 이것이 조기 최적화인지 여부는 실제로 이것이 어디서 어떻게 호출되는지에 달려 있습니다.
Spacemoose

5

ppc 아키텍처에는 비트 카운팅 명령이 있습니다. 이를 통해 단일 명령어로 양의 정수의 로그베이스 2를 결정할 수 있습니다. 예를 들어 32 비트는 다음과 같습니다.

#define log_2_32_ppc(x) (31-__cntlzw(x))

큰 값에서 작은 오차 한계를 처리 할 수있는 경우 다른 몇 가지 지침을 사용하여 오류를 로그 10으로 변환 할 수 있습니다.

#define log_10_estimate_32_ppc(x) (9-(((__cntlzw(x)*1233)+1545)>>12))

이것은 플랫폼에 따라 다르고 약간 부정확하지만 분기, 나누기 또는 부동 소수점으로의 변환이 필요하지 않습니다. 모두 필요한 것에 달려 있습니다.

ppc 명령어 만 알고 있지만 다른 아키텍처에도 비슷한 명령어가 있어야합니다.


이 솔루션은 log2 (15) = 4 비트 및 log2 (9) = 4 비트를 계산합니다. 그러나 15와 9는 다른 숫자의 10 진수를 인쇄해야합니다. 때로는 숫자가 너무 많은 숫자로 인쇄하는 것을 신경 쓰지 않으면 작동하지 않습니다. 그러나이 경우에는 항상 "10"을 int의 답변으로 선택할 수 있습니다.
Ira Baxter

와우, 대략적인 기능. 좋은.
doug65536

4
 #include <iostream>
 #include <math.h>

 using namespace std;

 int main()
 {
     double num;
     int result;
     cout<<"Enter a number to find the number of digits,  not including decimal places: ";
     cin>>num;
     result = ((num<=1)? 1 : log10(num)+1);
     cout<<"Number of digits "<<result<<endl;
     return 0;
 }

소수점 이하 자릿수 만 신경 쓰고 10보다 작은 숫자는 1 자리라고 가정하면 문제를 해결하는 가장 간단한 방법 일 것입니다.


1

Ira Baxter의 답변이 마음에 듭니다. 다음은 다양한 크기를 처리하고 최대 정수 값을 처리하는 템플릿 변형입니다 (루프에서 상한 점검을 수행하도록 업데이트 됨).

#include <boost/integer_traits.hpp>

template<typename T> T max_decimal()
{
    T t = 1;

    for (unsigned i = boost::integer_traits<T>::digits10; i; --i)
        t *= 10;

    return t;
}

template<typename T>
unsigned digits(T v)
{
    if (v < 0) v = -v;

    if (max_decimal<T>() <= v)
        return boost::integer_traits<T>::digits10 + 1;

    unsigned digits = 1;
    T boundary = 10;

    while (boundary <= v) {
        boundary *= 10;
        ++digits;
    }

    return digits;
}

루프에서 추가 테스트를 수행하여 실제로 성능을 향상 시키려면 플랫폼의 각 유형에 대한 상수를 반환하도록 max_decimal ()을 특수화해야합니다. 충분히 마술적인 컴파일러는 max_decimal ()에 대한 호출을 상수로 최적화 할 수 있지만 오늘날 대부분의 컴파일러에서는 전문화가 더 좋습니다. max_decimal이 루프에서 제거 된 테스트보다 비용이 많이 들기 때문에이 버전이 더 느릴 수 있습니다.

모든 것을 독자의 연습으로 남겨 두겠습니다.


각 루프 반복에서 확인하지 않도록 상한 확인을 별도의 조건 테스트를 먼저 수행하려고합니다.
Ira Baxter

그 온도에 10을 넣고 싶지 않습니다. 컴파일러는 실제 변수를 곱하는 것으로 t를 곱하는 것을 고려하고 범용 곱셈 명령어를 사용할 수 있습니다. 대신 "result * = 10;"을 쓴 경우 컴파일러는 상수 10을 곱한 것을 확실히 인식하고 몇 번의 시프트와 추가로 구현합니다. 매우 빠릅니다.
Ira Baxter

t에 의한 곱셈이 항상 10에 의한 곱셈이라면, 컴파일러는 강도를 감소시킬 수 있습니다. 그러나 t는이 경우 루프 불변성이 아닙니다 (내가 거짓말 한 정수 전력 함수의 수정 일뿐입니다). 올바른 최적화는 상수를 반환하는 유형에 대한 전문화입니다. 그러나이 경우 함수는 항상 임의의 정수가 아닌 10의 거듭 제곱을 올리는 것이 옳습니다. 강도 감소는 좋은 승리를 제공합니다. 그래서 변경했습니다 ... 이번에는 추가 변경 사항이 실제로 연습으로 남겨졌습니다! (스택 오버플로는 큰 시간 싱크입니다 ...)
janm September

1
#include <stdint.h> // uint32_t [available since C99]

/// Determine the number of digits for a 32 bit integer.
/// - Uses at most 4 comparisons.
/// - (cX) 2014 adolfo.dimare@gmail.com
/// - \see http://stackoverflow.com/questions/1489830/#27669966
/**  #d == Number length vs Number of comparisons == #c
     \code
         #d | #c   #d | #c
         ---+---   ---+---
         10 | 4     5 | 4
          9 | 4     4 | 4
          8 | 3     3 | 3
          7 | 3     2 | 3
          6 | 3     1 | 3
     \endcode
*/
unsigned NumDigits32bs(uint32_t x) {
    return // Num-># Digits->[0-9] 32->bits bs->Binary Search
    ( x >= 100000u // [6-10] [1-5]
    ?   // [6-10]
        ( x >= 10000000u // [8-10] [6-7]
        ?   // [8-10]
            ( x >= 100000000u // [9-10] [8]
            ? // [9-10]
                ( x >=  1000000000u // [10] [9]
                ?   10
                :    9
                )
            : 8
            )
        :   // [6-7]
            ( x >=  1000000u // [7] [6]
            ?   7
            :   6
            )
        )
    :   // [1-5]
        ( x >= 100u // [3-5] [1-2]
        ?   // [3-5]
            ( x >= 1000u // [4-5] [3]
            ? // [4-5]
                ( x >=  10000u // [5] [4]
                ?   5
                :   4
                )
            : 3
            )
        :   // [1-2]
            ( x >=  10u // [2] [1]
            ?   2
            :   1
            )
        )
    );
}

0

또 다른 코드 스 니펫은 기본적으로 Vitali와 동일하지만 이진 검색을 사용합니다. Powers 배열은 서명되지 않은 유형 인스턴스마다 한 번씩 지연 초기화됩니다. 부호있는 유형 과부하는 빼기 부호를 처리합니다.

#include <limits>
#include <type_traits>
#include <array>

template <class T> 
size_t NumberOfDecPositions ( T v, typename std::enable_if<std::is_unsigned<T>::value>::type* = 0 )
{
    typedef std::array<T,std::numeric_limits<T>::digits10+1> array_type;
    static array_type powers_of_10;
    if ( powers_of_10.front() == 0 )
    {
        T n = 1;
        for ( T& i: powers_of_10 )
        {
            i = n;
            n *= 10;
        }
    }

    size_t l = 0, r = powers_of_10.size(), p;
    while ( l+1 < r )
    {
        p = (l+r)/2;
        if ( powers_of_10[p] <= v )
            l = p;
        else
            r = p;
    }
    return l + 1;
};

template <class T> 
size_t NumberOfDecPositions ( T v, typename std::enable_if<std::is_signed<T>::value>::type* = 0 )
{
    typedef typename std::make_unsigned<T>::type unsigned_type;
    if ( v < 0 )
        return NumberOfDecPositions ( static_cast<unsigned_type>(-v) ) + 1;
    else
        return NumberOfDecPositions ( static_cast<unsigned_type>(v) );
}

더 이상의 최적화가 필요한 경우 powers 배열의 첫 번째 요소는 사용되지 않으며이 l표시는 +12 번 나타납니다 .


0

자릿수 각 자릿수 위치의 값이 필요한 경우 다음을 사용하십시오.

int64_t = number, digitValue, digits = 0;    // or "int" for 32bit

while (number != 0) {
    digitValue = number % 10;
    digits ++;
    number /= 10;
}

digit루프에서 현재 처리되는 숫자 위치의 값을 제공합니다. 예를 들어 숫자 1776의 경우 숫자 값은 다음과 같습니다.
1 번째 루프
7의 2 번째 루프
7 7 번째 루프
1의 4 번째 루프 1


0
// Meta-program to calculate number of digits in (unsigned) 'N'.    
template <unsigned long long N, unsigned base=10>
struct numberlength
{   // http://stackoverflow.com/questions/1489830/
    enum { value = ( 1<=N && N<base ? 1 : 1+numberlength<N/base, base>::value ) };
};

template <unsigned base>
struct numberlength<0, base>
{
    enum { value = 1 };
};

{
    assert( (1 == numberlength<0,10>::value) );
}
assert( (1 == numberlength<1,10>::value) );
assert( (1 == numberlength<5,10>::value) );
assert( (1 == numberlength<9,10>::value) );

assert( (4 == numberlength<1000,10>::value) );
assert( (4 == numberlength<5000,10>::value) );
assert( (4 == numberlength<9999,10>::value) );

위의 'blinnov.com'에서 "실제 농담"수정
Adolfo

0
/// Determine the number of digits for a 64 bit integer.
/// - Uses at most 5 comparisons.
/// - (cX) 2014 adolfo.dimare@gmail.com
/// - \see http://stackoverflow.com/questions/1489830/#27670035
/**  #d == Number length vs Number of comparisons == #c
     \code
         #d | #c   #d | #c     #d | #c   #d | #c
         ---+---   ---+---     ---+---   ---+---
         20 | 5    15 | 5      10 | 5     5 | 5
         19 | 5    14 | 5       9 | 5     4 | 5
         18 | 4    13 | 4       8 | 4     3 | 4
         17 | 4    12 | 4       7 | 4     2 | 4
         16 | 4    11 | 4       6 | 4     1 | 4
     \endcode
*/
unsigned NumDigits64bs(uint64_t x) {
    return // Num-># Digits->[0-9] 64->bits bs->Binary Search
    ( x >= 10000000000ul // [11-20] [1-10]
    ?
        ( x >= 1000000000000000ul // [16-20] [11-15]
        ?   // [16-20]
            ( x >= 100000000000000000ul // [18-20] [16-17]
            ?   // [18-20]
                ( x >= 1000000000000000000ul // [19-20] [18]
                ? // [19-20]
                    ( x >=  10000000000000000000ul // [20] [19]
                    ?   20
                    :   19
                    )
                : 18
                )
            :   // [16-17]
                ( x >=  10000000000000000ul // [17] [16]
                ?   17
                :   16
                )
            )
        :   // [11-15]
            ( x >= 1000000000000ul // [13-15] [11-12]
            ?   // [13-15]
                ( x >= 10000000000000ul // [14-15] [13]
                ? // [14-15]
                    ( x >=  100000000000000ul // [15] [14]
                    ?   15
                    :   14
                    )
                : 13
                )
            :   // [11-12]
                ( x >=  100000000000ul // [12] [11]
                ?   12
                :   11
                )
            )
        )
    :   // [1-10]
        ( x >= 100000ul // [6-10] [1-5]
        ?   // [6-10]
            ( x >= 10000000ul // [8-10] [6-7]
            ?   // [8-10]
                ( x >= 100000000ul // [9-10] [8]
                ? // [9-10]
                    ( x >=  1000000000ul // [10] [9]
                    ?   10
                    :    9
                    )
                : 8
                )
            :   // [6-7]
                ( x >=  1000000ul // [7] [6]
                ?   7
                :   6
                )
            )
        :   // [1-5]
            ( x >= 100ul // [3-5] [1-2]
            ?   // [3-5]
                ( x >= 1000ul // [4-5] [3]
                ? // [4-5]
                    ( x >=  10000ul // [5] [4]
                    ?   5
                    :   4
                    )
                : 3
                )
            :   // [1-2]
                ( x >=  10ul // [2] [1]
                ?   2
                :   1
                )
            )
        )
    );
}

0

정수 'X'의 경우 루프를 사용하지 않고 자릿수를 알고 싶습니다.이 솔루션은 한 줄로 하나의 수식으로 만 작동 하므로이 문제에 대해 가장 최적의 솔루션입니다.

 int x = 1000 ; 
 cout<<numberOfDigits = 1+floor(log10(x))<<endl ; 

INT_MAX 및 음수에 대해 실패합니다.
ranu

@ranu가 INT_MAX에 실패한 이유는 무엇입니까? 인수가 double? 로 변환 될 때 아니면 INT_MAX 십진수로 불가능한 정수 입력을 언급하고 있습니까? 어느 쪽도 다른 대답에 모두 실패합니까?
Lorne의 후작

0
int numberOfDigits(int n){

    if(n<=9){
        return 1;
    }
    return 1 + numberOfDigits(n/10);
}

이것은 기본 10에 대해 원하는 경우 수행 할 작업입니다. 매우 빠르며 정수를 계산하는 스택 오버플로 구매를 얻지 못할 것입니다.


0
int num,dig_quant = 0;
cout<<"\n\n\t\t--Count the digits in Number--\n\n";
cout<<"Enter Number: ";
cin>>num;
for(int i = 1; i<=num; i*=10){
    if(num / i  > 0){
      dig_quant += 1;
    }
}
 cout<<"\n"<<number<<" include "<<dig_quant<<" digit"
 cout<<"\n\nGoodbye...\n\n";

0

더 빠를수록 더 효율적이며, andrei alexandrescu의 개선 입니다. 그의 버전은 이미 순진한 방법보다 빠르다 (모든 숫자에서 10으로 나눔). 아래 버전은 모든 크기의 x86-64 및 ARM에서 일정 시간 이상 빨라지지만 이진 코드의 두 배를 차지하므로 캐시 친화적이지 않습니다.

이 버전의 벤치 마크 와 페이스 북의PR에서 alexandrescu의 버전은 folly 입니다.

작동 unsigned하지 않습니다 signed.

inline uint32_t digits10(uint64_t v) {
  return  1
        + (std::uint32_t)(v>=10)
        + (std::uint32_t)(v>=100)
        + (std::uint32_t)(v>=1000)
        + (std::uint32_t)(v>=10000)
        + (std::uint32_t)(v>=100000)
        + (std::uint32_t)(v>=1000000)
        + (std::uint32_t)(v>=10000000)
        + (std::uint32_t)(v>=100000000)
        + (std::uint32_t)(v>=1000000000)
        + (std::uint32_t)(v>=10000000000ull)
        + (std::uint32_t)(v>=100000000000ull)
        + (std::uint32_t)(v>=1000000000000ull)
        + (std::uint32_t)(v>=10000000000000ull)
        + (std::uint32_t)(v>=100000000000000ull)
        + (std::uint32_t)(v>=1000000000000000ull)
        + (std::uint32_t)(v>=10000000000000000ull)
        + (std::uint32_t)(v>=100000000000000000ull)
        + (std::uint32_t)(v>=1000000000000000000ull)
        + (std::uint32_t)(v>=10000000000000000000ull);
}

0

사용자가 숫자에 몇 자릿수가 있는지 정확하게 대답했는지 확인 해야하는 프로그램을 개발하고 있었으므로 정수의 자릿수를 확인하는 방법을 개발해야했습니다. 결국 비교적 쉽게 해결할 수 있습니다.

double check=0, exponent=1000;

while(check<=1)
{
    check=number/pow(10, exponent);
    exponent--;
}

exponent=exponent+2;
cout<<exponent<<endl;

이것은 내 대답으로 끝났으며 현재 10 ^ 1000 자릿수 미만의 숫자로 작동합니다 (지수 값을 변경하여 변경할 수 있음).

추신 : 나는이 답변이 10 년 늦었다는 것을 알고 있지만 2020 년에 도착하여 다른 사람들이 사용할 수 있습니다.


-1
template <typename type>
class number_of_decimal_digits {   
    const powers_and_max<type> mPowersAndMax;
public:
    number_of_decimal_digits(){
    }   
    inline size_t ndigits( type i) const {
        if(i<0){
             i += (i == std::numeric_limits<type>::min());
             i=-i;
        }
        const type* begin = &*mPowersAndMax.begin();
        const type* end = begin+mPowersAndMax.size();
        return 1 + std::lower_bound(begin,end,i) - begin;
    }
    inline size_t string_ndigits(const type& i) const {
        return (i<0) + ndigits(i);
    }
    inline size_t operator[](const type& i) const {
       return string_ndigits(i);
    }
};

에 여기서 powers_and_max우리는이 (10^n)-1모든 n그러한

(10^n) < std::numeric_limits<type>::max()

그리고 std::numeric_limits<type>::max()배열에서 :

template <typename type>
struct powers_and_max : protected std::vector<type>{
    typedef std::vector<type> super;
    using super::const_iterator;
    using super::size;
    type& operator[](size_t i)const{return super::operator[](i)};
    const_iterator begin()const {return super::begin();} 
    const_iterator end()const {return super::end();} 
    powers_and_max() {
       const int size = (int)(log10(double(std::numeric_limits<type>::max())));
       int j = 0;
       type i = 10;
       for( ; j<size ;++j){
           push_back(i-1);//9,99,999,9999 etc;
           i*=10;
       }
       ASSERT(back()<std::numeric_limits<type>::max());
       push_back(std::numeric_limits<type>::max());
   }
};

다음은 간단한 테스트입니다.

number_of_decimal_digits<int>  ndd;
ASSERT(ndd[0]==1);
ASSERT(ndd[9]==1);
ASSERT(ndd[10]==2);
ASSERT(ndd[-10]==3);
ASSERT(ndd[-1]==2);
ASSERT(ndd[-9]==2);
ASSERT(ndd[1000000000]==10);
ASSERT(ndd[0x7fffffff]==10);
ASSERT(ndd[-1000000000]==11);
ASSERT(ndd[0x80000000]==11);

물론, 순서화 된 세트의 다른 구현이 사용될 powers_and_max수 있으며 클러스터링에 대한 지식은 있지만 클러스터가 자체 조정 트리 구현이 될 수있는 위치에 대한 지식이없는 경우 가장 좋습니다.


-1

효과적인 방법

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

#include <iostream>

int main()
{
   int num;
   std::cin >> num;

   std::cout << "number of digits for " << num << ": ";

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

   std::cout << count << '\n';

   return 0;
}

-1

선호하는 솔루션의 C ++ 11 업데이트 :

#include <limits>
#include <type_traits>
        template <typename T>
        typename std::enable_if<std::numeric_limits<T>::is_integer, unsigned int>::type
        numberDigits(T value) {
            unsigned int digits = 0;
            if (value < 0) digits = 1;
            while (value) {
                value /= 10;
                ++digits;
            }
            return digits;
        }

double 등으로 템플릿 인스턴스화를 방지합니다. 알.


-1
int numberOfDigits(double number){
    if(number < 0){
        number*=-1;
    }
    int i=0;
        while(number > pow(10, i))
            i++;    
    cout << "This number has " << i << " digits" << endl;
    return i;
}

-2

이것이 내 방법입니다.

   int digitcount(int n)
    {
        int count = 1;
        int temp = n;
        while (true)
        {
            temp /= 10;
            if (temp != 0) ++count;
            if (temp == 0) break;
        }

        return count;
    }

2
true / break syndrome 동안 : D
Петър Петров

-1 이것은 6 년 전의 첫 번째 대답과 같은 접근법이며, 아무 것도 추가하지 않습니다 (사실 심각하게 나쁩니다).

-4

다른 접근 방식은 다음과 같습니다.

digits = sprintf(numArr, "%d", num);    // where numArr is a char array
if (num < 0)
    digits--;

이것은 효율적이지 않을 수 있으며 다른 사람들이 제안한 것과는 다른 것입니다.


4
요청은 매우 효율적이었습니다. 이것은 반대입니다.
Ira Baxter
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.