Cách hiệu quả để xác định số chữ số trong một số nguyên


144

Một cách rất hiệu quả để xác định có bao nhiêu chữ số trong một số nguyên trong C ++ là gì?


11
Ở cơ sở nào? 2? 10?
Jacob Krall

2
Tôi muốn làm điều đó trong cơ sở 10
Seth

1
Tôi đã từng hỏi một câu hỏi liên quan: Làm thế nào bạn có thể có được chữ số đầu tiên trong một int? Nhiều phương pháp tương tự như dưới đây đã được sử dụng trong câu trả lời của mọi người. Đây là liên kết trong trường hợp liên quan đến nhiệm vụ của bạn [ stackoverflow.com/questions/701322/]
Dinah

Liệu lắp ráp nội tuyến có đủ điều kiện?
Gyorgy Andottok

1
Mặc dù tất cả các câu trả lời này đều dựa trên cơ sở 10, nhưng khá dễ dàng để thay đổi để tính kết quả cho bất kỳ cơ sở mong muốn nào.
Ira Baxter

Câu trả lời:


106

Chà, cách hiệu quả nhất, giả sử bạn biết kích thước của số nguyên, sẽ là một tra cứu. Nên nhanh hơn cách tiếp cận dựa trên logarit ngắn hơn nhiều. Nếu bạn không quan tâm đến việc đếm '-', hãy xóa +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
Có lẽ nhanh hơn câu trả lời của tôi, cũng được thực hiện. Để tăng thêm hiệu quả, nếu bạn biết rằng số đầu vào của bạn sẽ chủ yếu là số nhỏ (tôi đoán dưới 100.000), sau đó đảo ngược các bài kiểm tra: if (x <10) trả về 1; nếu (x <100) trả về 2; vv, do đó, chức năng sẽ làm ít bài kiểm tra và thoát nhanh hơn.
squelart

29
Hoặc có lẽ sắp xếp lại và lồng các câu lệnh if, để thực hiện tìm kiếm nhị phân thay vì tìm kiếm tuyến tính.
dave4420

1
Đó không phải là một ý tưởng hay. Điều gì xảy ra khi kiến ​​trúc mở rộng thành số nguyên 256 bit. Bạn cần nhớ quay lại và sửa đổi mã này. Trong cuộc sống thực sẽ không xảy ra và điều này có lẽ sẽ được sử dụng để xây dựng một bộ đệm có kích thước chính xác mà bạn hiện đang mở cho mình tất cả các loại bộ đệm trong các vấn đề chạy trên các kiến ​​trúc sư lớn hơn.
Martin York

3
giả sử phân phối số đồng đều, tìm kiếm tuyến tính ngược (bắt đầu từ chữ số tối đa đến 1) có thể nhanh hơn trung bình so với tìm kiếm nhị phân vì có khá nhiều số có chữ số N so với chữ số N-1 Graphics.stanford.edu/~ seander / Quang
fa.

6
Tôi sẽ không lo lắng nhiều về số nguyên 256 hoặc 128 bit. Trừ khi bạn cần đếm số lượng electron trong Vũ trụ (10 ^ 78 lần trước tôi đã làm điều đó), 64 bit sẽ hoạt động khá tốt. Máy 32 bit kéo dài ~ 15 năm. Tôi đoán máy 64 bit sẽ tồn tại lâu hơn nhiều. Đối với số lượng lớn hơn, số học đa số sẽ ổn, và tôi nghi ngờ nếu hiệu quả của việc tính toán số chữ số sẽ có vấn đề.
Ira Baxter

74

Cách đơn giản nhất là làm:

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

log10 được định nghĩa trong <cmath>hoặc <math.h>. Bạn cần phải lập hồ sơ này để xem nó có nhanh hơn bất kỳ bài nào khác được đăng ở đây không. Tôi không chắc điều này mạnh đến mức nào về độ chính xác của điểm nổi. Ngoài ra, đối số không được ký là giá trị âm và nhật ký không thực sự trộn lẫn.


7
Đối với ints 32 bit và float 56 bit, điều này có thể hoạt động. Nếu đầu vào dài (64 bit), 56 bit của nhật ký độ chính xác kép có thể khiến điều này tạo ra câu trả lời sai trong trường hợp giá trị gần giá trị lớn 10 ^ n. Mong đợi sự cố trên 2 ^ 50.
Ira Baxter

1
Ngoài ra còn có câu hỏi về mức độ chính xác của các chức năng đăng nhập. Tôi đã không kiểm tra độ chính xác của chúng trong các thư viện hiện đại và sẽ không thoải mái khi tin tưởng chúng sẽ tốt với một phần trong một tỷ.
David Thornley

@DavidThornley: log hoặc các hàm toán học khác hoàn toàn chính xác trừ khi được chỉ định trên dòng lệnh của trình biên dịch. một số sẽ được chuyển đổi thành x86 nội tại tại thời điểm biên dịch. một số không tồn tại và sẽ mở rộng thành các công thức của nội tại hiện có. ví dụ: nếu sử dụng, -fpfastbạn có thể thấy việc sử dụng SSE Barsinsics thay vì x87, điều này mang lại ít đảm bảo hơn cho IIRC chính xác. nhưng theo mặc định không có vấn đề.
v.oddou

@DavidThornley: Nó còn hơn cả chính xác. Câu hỏi đặt ra là nó có được đảm bảo hay không mà log10 (10 ^ k) k cho tất cả các k có liên quan. Đó là nó được đảm bảo rằng bất kỳ lỗi làm tròn không thể tránh khỏi đi đúng hướng. k + eps là kết quả hoạt động, k - eps không. Và "Hoàn toàn chính xác" là ngây thơ.
gnasher729

1
Thử nghiệm i> 0 có thể được tối ưu hóa thành i> 9
Pat

60

Có lẽ tôi đã hiểu nhầm câu hỏi nhưng điều này không làm được?

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
Và tôi sẽ không ngạc nhiên nếu giải pháp này sẽ nhanh nhất.
VisioN

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

Lưu ý: "0" sẽ có 0 chữ số! Nếu bạn cần 0 để xuất hiện để có 1 chữ số, hãy sử dụng:

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

(Cảm ơn Kevin Fegan)

Cuối cùng, hãy sử dụng một hồ sơ để biết câu trả lời nào trong số này sẽ nhanh hơn trên máy của bạn ...


3
Điều này có thể hoặc không thể nhanh hơn cách tiếp cận vòng lặp không được kiểm soát mà tôi đã thực hiện - bạn cần xác định sự khác biệt (nên không đáng kể trong thời gian dài).
Vitali

Đồng ý, hồ sơ là cách duy nhất để thực sự biết chắc chắn! Tôi đã cập nhật câu trả lời của mình với nhận xét đó, vì câu trả lời của Ben S (log10 ()) đã biến mất.
squelart

11

Thực tiễn đùa: Đây là những cách hiệu quả nhất (số chữ số được tính tại thời gian biên dịch):

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

Có thể hữu ích để xác định độ rộng cần thiết cho trường số trong định dạng, thành phần đầu vào, v.v.


4
Đầu tiên, giải pháp của bạn không hoạt động trong 0. Thứ hai, giải pháp của bạn không thể áp dụng được cho trường hợp chung của một biến. Thứ ba, nếu bạn đang sử dụng một chữ không đổi, bạn đã biết nó có bao nhiêu chữ số.
Vitali

Nó hoạt động cho 0 quá. Nó cũng hoạt động cho bất kỳ cơ sở. Phần còn lại là những điểm hợp lệ mà tôi đã vạch ra.
blinnov.com

3
Tôi không nghĩ rằng nó thực sự. Nó không thành công 0và cũng thất bại trên cơ sở 1:) và phân chia cho các lỗi bằng 0 nếu cơ sở được đưa ra là 0. Nó có thể được sửa chữa mặc dù. Dù sao, tôi đang viết về một bài viết rất cũ, rất xin lỗi, chỉ là tôi nghĩ rằng đây không phải là một trò đùa và thực sự có thể hữu ích.
tjm

9

Xem Bit Twiddling Hacks để biết phiên bản ngắn hơn của câu trả lời mà bạn đã chấp nhận. Nó cũng có lợi ích là tìm ra câu trả lời sớm hơn nếu đầu vào của bạn được phân phối bình thường, bằng cách kiểm tra các hằng số lớn trước. (v >= 1000000000)nắm bắt 76% giá trị, do đó, việc kiểm tra đầu tiên sẽ trung bình nhanh hơn.


Không rõ liệu twiddling thực sự nhanh hơn. Ngay cả trong trường hợp xấu nhất, cách tiếp cận được sửa đổi của tôi yêu cầu 4 so sánh (có thể giảm xuống còn 3 nếu tôi kiểm tra phân vùng hơn nữa, mặc dù điều đó có vẻ không ổn). Tôi thực sự nghi ngờ rằng điều đó sẽ bị đánh bại bởi các hoạt động số học + tải bộ nhớ (mặc dù nếu được truy cập đủ, những thứ đó sẽ biến mất trong bộ đệm CPU). Hãy nhớ rằng, trong ví dụ họ đưa ra, họ cũng ẩn cơ sở nhật ký 2 dưới dạng một số hàm IntegerLogBase2 trừu tượng (bản thân nó thực sự không rẻ).
Vitali

Cũng giống như theo dõi, có nếu các số được phân phối bình thường, thực hiện kiểm tra theo thứ tự nhanh hơn. Tuy nhiên, nó có trường hợp thoái hóa là chậm gấp đôi trong trường hợp xấu nhất. Cách tiếp cận được phân vùng theo số chữ số thay vì không gian đầu vào có nghĩa là hành vi không có trường hợp suy biến và luôn thực hiện tối ưu. Hơn nữa, hãy nhớ rằng bạn đang đưa ra giả định rằng các số sẽ được phân phối đồng đều. Trên thực tế, nhiều khả năng họ sẽ theo dõi một số phân phối liên quan đến <a href=" en.wikipedia.org/wiki/iêu> sẽ là dự đoán của tôi
Vitali

Các hack đột biến bit không nhanh hơn phương pháp phân vùng ở trên, nhưng chúng có khả năng thú vị nếu bạn có một trường hợp tổng quát hơn như nổi ở đây.
Corwin Joy

1
Các bản hack twiddling gợi ý một cách để lấy int log10, được cung cấp int log2. Nó gợi ý một số cách để có được int log2, chủ yếu liên quan đến một vài so sánh / nhánh. (Tôi nghĩ rằng bạn đang đánh giá thấp chi phí của các chi nhánh không thể đoán trước, Vitali). Nếu bạn có thể sử dụng x86 asm nội tuyến, lệnh BSR sẽ cung cấp cho bạn int log2 của một giá trị (tức là chỉ số bit của bit được thiết lập quan trọng nhất). Đó là một chút chậm trên K8 (độ trễ 10 chu kỳ), nhưng nhanh trên Core 2 (độ trễ 2 hoặc 3 chu kỳ). Ngay cả trên K8, cũng có thể nhanh hơn so với so sánh.
Peter Cordes

Trên K10, lzcnt đếm các số 0 đứng đầu, do đó, nó gần giống như bsr, nhưng đầu vào bằng 0 không còn là trường hợp đặc biệt với kết quả không xác định. Độ trễ: BSR: 4, LZCNT: 2.
Peter Cordes

8

chuyển đổi thành chuỗi và sau đó sử dụng các hàm dựng sẵn

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
Mặc dù điều này là hiệu quả về mặt LỘC, như đã lưu ý trong câu trả lời được chấp nhận sử dụng nhật ký có thể sẽ không cho hiệu suất tốt nhất.
Ian

@Ian Tại sao không? Đó chỉ là một vài hướng dẫn của FPU. Miles tốt hơn so với tất cả các chi nhánh và vòng lặp trong câu trả lời khác.
Hầu tước Lorne

5

Một poster trước đã đề xuất một vòng lặp chia cho 10. Vì bội số trên các máy hiện đại nhanh hơn rất nhiều, nên tôi khuyên bạn nên sử dụng mã sau:

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

1
ma quỷ nằm trong chi tiết - điều xảy ra với say std :: num_limits <int> :: max == number - nó có thể có vấn đề chấm dứt
pgast

2
Nếu bạn lo lắng về trường hợp đó, bạn có thể thêm một IF bổ sung để xử lý các giá trị rất lớn.
Ira Baxter

2
Tôi nên quan sát rằng trên các máy x86, nhân với hằng số 10 như được sử dụng trong trường hợp này thực sự có thể được trình biên dịch triển khai như LEA R2, [8 * R1 + R1], ADD R1, R2 để có tối đa 2 đồng hồ. Nhân với các biến mất hàng chục đồng hồ, và sự phân chia tồi tệ hơn nhiều.
Ira Baxter

lợi thế của phương pháp phân chia là bạn không cần phải lo lắng về số âm.
Julian Schaub - litb

1
Tôi đã điểm chuẩn phương pháp nhân (với một fabs để loại bỏ vấn đề dấu hiệu) so với phương pháp phân chia. Trên máy của tôi, cách tiếp cận chia là yếu tố 2 chậm hơn so với cách tiếp cận nhân. Việc này có phải là tối ưu hóa sớm hay không thực sự phụ thuộc vào vị trí và cách gọi của nó.
Spacemoose

5

Kiến trúc ppc có một hướng dẫn đếm bit. Cùng với đó, bạn có thể xác định cơ sở nhật ký 2 của một số nguyên dương trong một lệnh. Ví dụ: 32 bit sẽ là:

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

Nếu bạn có thể xử lý một lỗi sai nhỏ trên các giá trị lớn, bạn có thể chuyển đổi nó thành nhật ký cơ sở 10 bằng một vài hướng dẫn khác:

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

Đây là nền tảng cụ thể và hơi không chính xác, nhưng cũng không liên quan đến chi nhánh, phân chia hoặc chuyển đổi thành điểm nổi. Tất cả phụ thuộc vào những gì bạn cần.

Tôi chỉ biết các hướng dẫn ppc ngoài tay, nhưng các kiến ​​trúc khác nên có hướng dẫn tương tự.


Giải pháp này tính toán log2 (15) = 4 bit và log2 (9) = 4 bit. Nhưng 15 và 9 yêu cầu số chữ số thập phân khác nhau để in. Vì vậy, nó không hoạt động, trừ khi đôi khi bạn không nhớ số của mình in quá nhiều chữ số. Nhưng trong trường hợp đó, bạn luôn có thể chọn "10" làm câu trả lời cho int.
Ira Baxter

Wow, một chức năng gần đúng. Đẹp.
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;
 }

Đây có lẽ là cách đơn giản nhất để giải quyết vấn đề của bạn, giả sử bạn chỉ quan tâm đến các chữ số trước số thập phân và giả sử mọi thứ nhỏ hơn 10 chỉ là 1 chữ số.


1

Tôi thích câu trả lời của Ira Baxter. Dưới đây là một biến thể mẫu xử lý các kích thước khác nhau và xử lý các giá trị số nguyên tối đa (được cập nhật để nâng thanh tra giới hạn trên của vòng lặp):

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

Để thực sự có được hiệu suất được cải thiện từ việc nâng thử nghiệm bổ sung ra khỏi vòng lặp, bạn cần phải chuyên biệt max_decimal () để trả về hằng số cho từng loại trên nền tảng của bạn. Một trình biên dịch ma thuật đủ có thể tối ưu hóa cuộc gọi thành max_decimal () thành một hằng số, nhưng chuyên môn hóa tốt hơn với hầu hết các trình biên dịch ngày nay. Như hiện tại, phiên bản này có thể chậm hơn vì chi phí tối đa nhiều hơn so với các thử nghiệm được loại bỏ khỏi vòng lặp.

Tôi sẽ để lại tất cả những điều đó như một bài tập cho người đọc.


Bạn muốn làm cho giới hạn trên kiểm tra một điều kiện riêng biệt được kiểm tra trước để bạn không kiểm tra nó trên mỗi lần lặp.
Baxter

Bạn không muốn đặt 10 vào temp t đó. Trình biên dịch có thể xem xét nhân với t để nhân với một biến thực và sử dụng một lệnh nhân đa mục đích chung. Thay vào đó, nếu bạn viết "kết quả * = 10;" trình biên dịch chắc chắn sẽ chú ý nhân với hằng số 10 và thực hiện điều đó với một vài thay đổi và bổ sung, cực kỳ nhanh.
Baxter

Nếu phép nhân với t luôn là một phép nhân với 10, thì có, trình biên dịch có thể làm giảm sức mạnh. Tuy nhiên, t không phải là bất biến vòng lặp trong trường hợp này (nó chỉ là một sửa đổi của hàm số nguyên mà tôi đã nằm xung quanh). Tối ưu hóa chính xác là chuyên môn hóa về loại trả về một hằng số. Tuy nhiên, bạn đã đúng rằng, trong trường hợp này, hàm luôn tăng 10 thành một lũy thừa, không phải là một số nguyên tùy ý cho một sức mạnh và giảm sức mạnh mang lại một chiến thắng tốt. Vì vậy, tôi đã thực hiện một thay đổi ... Lần này những thay đổi tiếp theo thực sự là một bài tập! (Stack Overflow là một khoảng thời gian lớn ...)
janm

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

Một đoạn mã khác, về cơ bản giống như Vitali nhưng sử dụng tìm kiếm nhị phân. Mảng quyền hạn được lười biếng khởi tạo một lần cho mỗi thể hiện kiểu không dấu. Ký loại quá tải chăm sóc dấu trừ.

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

Nếu bất cứ ai quan tâm đến việc tối ưu hóa hơn nữa, xin lưu ý rằng phần tử đầu tiên của mảng lũy ​​thừa không bao giờ được sử dụng và lxuất hiện với +12 lần.


0

trong trường hợp số chữ số giá trị của từng vị trí chữ số là cần thiết, hãy sử dụng:

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

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

digitcung cấp cho bạn giá trị tại bài đăng số hiện đang được xử lý trong vòng lặp. ví dụ cho số 1776, giá trị chữ số là:
6 trong vòng 1
7 trong vòng 2 thứ
7 trong vòng 3 thứ
1 trong vòng 4


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

Sửa lỗi cho "Trò đùa thực tế" từ 'blinnov.com' ở trên
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

đối với số nguyên 'X' bạn muốn biết số chữ số, không cần sử dụng bất kỳ vòng lặp nào, giải pháp này chỉ hoạt động trong một công thức trong một dòng vì vậy đây là giải pháp tối ưu nhất tôi từng thấy cho vấn đề này.

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

Thất bại cho INT_MAX và cả cho số âm.
ranu

@ranu Thất bại cho INT_MAX thế nào? Khi đối số được chuyển đổi thành double? Hoặc bạn đang đề cập đến một số đầu vào số nguyên không thể có chữ số thập phân INT_MAX? Mà cũng sẽ thất bại mọi câu trả lời khác ở đây?
Hầu tước Lorne

0
int numberOfDigits(int n){

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

Đây là những gì tôi sẽ làm, nếu bạn muốn nó cho cơ sở 10. Tôi khá nhanh và bạn sẽ không nhận được một ngăn xếp quá mức mua số nguyên đếm


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

Nếu nhanh hơn là hiệu quả hơn, đây là một cải tiến về cải tiến của andrei alexandrescu . Phiên bản của anh ta đã nhanh hơn cách ngây thơ (chia cho 10 ở mỗi chữ số). Phiên bản dưới đây là thời gian không đổi và nhanh hơn ít nhất là trên x86-64 và ARM cho tất cả các kích cỡ, nhưng chiếm gấp đôi số mã nhị phân, vì vậy nó không thân thiện với bộ đệm.

Điểm chuẩn cho phiên bản này so với phiên bản của alexandrescu trên PR của tôi trên facebook .

Hoạt động trên unsigned, không 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

Tôi đang làm việc trên một chương trình yêu cầu tôi kiểm tra xem người dùng có trả lời đúng có bao nhiêu chữ số trong một số không, vì vậy tôi phải phát triển một cách để kiểm tra số lượng chữ số trong một số nguyên. Nó đã trở thành một điều tương đối dễ dàng để giải quyết.

double check=0, exponent=1000;

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

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

Đây là câu trả lời của tôi hiện đang hoạt động với các số có ít hơn 10 ^ 1000 chữ số (có thể thay đổi bằng cách thay đổi giá trị của số mũ).

Tái bút Tôi biết câu trả lời này trễ mười năm nhưng tôi đã đến đây vào năm 2020 để những người khác có thể sử dụng nó.


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

nơi mà trong powers_and_maxchúng ta có (10^n)-1cho tất cả n

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

std::numeric_limits<type>::max()trong một mảng:

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

đây là một bài kiểm tra đơn giản:

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

Tất nhiên, bất kỳ triển khai nào khác của một tập hợp có thể được sử dụng cho powers_and_maxvà nếu có kiến ​​thức rằng sẽ có cụm nhưng không có kiến ​​thức về nơi cụm có thể là một thực thi cây tự điều chỉnh có thể là tốt nhất


-1

cách hiệu quả

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ập nhật C ++ 11 của giải pháp ưa thích:

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

ngăn chặn việc khởi tạo mẫu với double, et. al.


-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

Đây là cách của tôi để làm điều đó:

   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
trong khi hội chứng / nghỉ đúng: D
Петър Петров

-1 đây là cách tiếp cận tương tự mà câu trả lời đầu tiên đưa ra sáu năm trước đó và nó không thêm gì cả (thực tế nó còn tệ hơn đáng kể).

-4

Đây là một cách tiếp cận khác:

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

Điều này có thể không hiệu quả, chỉ là một cái gì đó khác với những gì người khác đề xuất.


4
Yêu cầu là cực kỳ hiệu quả. Điều này ngược lại.
Ira Baxter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.