Cara efisien untuk menentukan jumlah digit dalam bilangan bulat

145

Apa cara yang sangat efisien untuk menentukan berapa digit yang ada dalam integer di C ++?

Seth
sumber
11
Di pangkalan apa? 2? 10?
Jacob Krall
2
Saya ingin melakukannya di basis 10
Seth
1
Saya pernah mengajukan pertanyaan terkait: Bagaimana Anda bisa mendapatkan digit pertama dalam sebuah int? Banyak metodologi yang sama seperti di bawah ini digunakan dalam jawaban orang. Berikut tautan jika itu relevan dengan tugas Anda [ stackoverflow.com/questions/701322/]
Dinah
Apakah perakitan inline memenuhi syarat?
György Andrasek
1
Meskipun semua jawaban ini terkait dengan basis 10, sangat mudah untuk mengubah untuk menghitung hasilnya untuk basis yang diinginkan.
Ira Baxter

Jawaban:

106

Nah, cara yang paling efisien, anggap Anda tahu ukuran bilangan bulat, akan menjadi pencarian. Harus lebih cepat daripada pendekatan berbasis logaritma yang jauh lebih pendek. Jika Anda tidak peduli tentang penghitungan '-', hapus +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];
}
Vitali
sumber
5
Mungkin lebih cepat dari jawaban saya, bagus sekali. Untuk efisiensi tambahan, jika Anda tahu bahwa jumlah input Anda sebagian besar kecil (saya kira kurang dari 100.000), maka balikkan tes: if (x <10) menghasilkan 1; jika (x <100) mengembalikan 2; dll., sehingga fungsi akan melakukan lebih sedikit tes dan keluar lebih cepat.
squelart
29
Atau mungkin menyusun ulang dan membuat pernyataan if, untuk melakukan pencarian biner alih-alih pencarian linear.
dave4420
1
Itu bukan ide yang bagus. Apa yang terjadi ketika arsitektur meluas ke bilangan bulat 256 bit. Anda harus ingat untuk kembali dan memodifikasi kode ini. Dalam kehidupan nyata yang tidak akan terjadi dan ini mungkin akan digunakan untuk membangun buffer dengan ukuran yang benar Anda sekarang membuka diri untuk segala macam buffer over run pada arsitek yang lebih besar.
Martin York
3
dengan asumsi distribusi angka yang seragam, pencarian linear terbalik (mulai dari angka maks ke 1) mungkin lebih cepat rata-rata daripada pencarian biner karena ada angka yang lebih banyak dengan angka N daripada angka grafis N-1.stanford.edu/~ seander / ...
fa.
6
Saya tidak akan terlalu khawatir tentang bilangan bulat 256 atau 128 bit. Kecuali jika Anda perlu menghitung jumlah elektron di Semesta (10 ^ 78 terakhir kali saya melakukannya), 64 bit akan bekerja dengan cukup baik. Mesin 32 bit bertahan ~~ 15 tahun. Saya kira mesin 64 bit akan bertahan lebih lama. Untuk jumlah yang lebih besar, aritmatika multiprecision akan baik-baik saja, dan saya ragu apakah efisiensi penghitungan jumlah digit akan berpengaruh.
Ira Baxter
74

Cara paling sederhana adalah dengan melakukan:

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

log10 didefinisikan dalam <cmath>atau <math.h>. Anda perlu membuat profil ini untuk melihat apakah ini lebih cepat daripada yang lain yang diposting di sini. Saya tidak yakin seberapa kuat ini dalam hal presisi float point. Juga, argumen tidak ditandatangani karena nilai negatif dan log tidak benar-benar tercampur.

Mendesis
sumber
7
Untuk 32 bit int dan 56 bit mengapung, ini mungkin berhasil. Jika inputnya panjang (64 bit), 56 bit dari log presisi ganda dapat menyebabkan ini menghasilkan jawaban yang salah dalam kasus nilai dekat nilai besar 10 ^ n. Harapkan masalah di atas 2 ^ 50.
Ira Baxter
1
Ada juga pertanyaan tentang seberapa akurat fungsi log. Saya belum memeriksa seberapa akurat mereka di perpustakaan modern, dan tidak akan nyaman membabi buta percaya bahwa mereka baik untuk satu bagian dalam satu miliar.
David Thornley
@ Davidvidhorn: log atau fungsi matematika lainnya sangat tepat kecuali ditentukan pada baris perintah kompiler. beberapa akan dikonversi menjadi intrinsik x86 pada waktu kompilasi. beberapa tidak ada dan akan berkembang menjadi formula intrinsik yang ada. misalnya jika menggunakan -fpfastAnda bisa melihat penggunaan instrinsik SSE daripada x87, yang menghasilkan lebih sedikit jaminan pada presisi IIRC. tetapi secara default tidak ada masalah.
v.oddou
@ Davidvidhorn: Ini lebih dari presisi. Pertanyaannya adalah apakah dijamin atau tidak log10 (10 ^ k) ≥ k untuk semua yang relevan k. Itu dijamin bahwa kesalahan pembulatan yang tak terelakkan pergi ke arah yang benar. k + eps sebagai hasilnya berfungsi, k - eps tidak. Dan "Tepat sekali" adalah naif.
gnasher729
1
Tes i> 0 dapat dioptimalkan ke i> 9
Pat
60

Mungkin saya salah paham pertanyaannya tetapi tidakkah ini berhasil?

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)))))))));  
}  
Brad
sumber
29
Dan saya tidak akan terkejut jika solusi ini akan menjadi yang tercepat.
VisioN
32
int digits = 0; while (number != 0) { number /= 10; digits++; }

Catatan: "0" akan memiliki 0 digit! Jika Anda perlu 0 untuk memiliki 1 digit, gunakan:

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

(Terima kasih Kevin Fegan)

Pada akhirnya, gunakan profiler untuk mengetahui mana dari semua jawaban di sini yang akan lebih cepat di mesin Anda ...

squelart
sumber
3
Ini mungkin atau mungkin tidak lebih cepat dari pendekatan loop terbuka yang saya ambil - Anda harus membuat profil perbedaan (harus diabaikan dalam jangka panjang).
Vitali
Setuju, membuat profil adalah satu-satunya cara untuk benar-benar tahu! Saya memperbarui jawaban saya dengan komentar itu, karena jawaban ceil (log10 ()) Ben S telah hilang.
squelart
11

Lelucon praktis: Ini adalah cara yang paling efisien (jumlah digit dihitung pada waktu kompilasi):

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

Mungkin bermanfaat untuk menentukan lebar yang diperlukan untuk bidang angka dalam pemformatan, elemen input dll.

blinnov.com
sumber
4
Pertama, solusi Anda tidak berfungsi untuk 0. Kedua solusi Anda tidak dapat diterapkan pada kasus umum suatu variabel. Ketiga, jika Anda menggunakan literal konstan, Anda sudah tahu berapa digit yang dimilikinya.
Vitali
Ini bekerja untuk 0 juga. Ini juga berfungsi untuk basis apa pun. Sisanya adalah poin valid yang sudah saya uraikan.
blinnov.com
3
Saya kira itu tidak benar. Gagal 0dan juga gagal pada basis 1:) dan memberikan bagi dengan kesalahan nol jika basis diberikan sebagai 0. Itu bisa diperbaiki. Pokoknya saya memilih posting yang sangat lama, jadi maaf, hanya saja saya pikir ini tidak perlu menjadi lelucon dan sebenarnya bisa berguna.
tjm
9

Lihat Bit Twiddling Hacks untuk versi yang jauh lebih pendek dari jawaban yang Anda terima. Ini juga memiliki keuntungan menemukan jawaban lebih cepat jika input Anda terdistribusi normal, dengan memeriksa konstanta besar terlebih dahulu. (v >= 1000000000)menangkap 76% dari nilai, jadi memeriksa yang pertama rata-rata akan lebih cepat.

Josh Haberman
sumber
Tidak jelas apakah bit-twiddling sebenarnya lebih cepat. Bahkan dalam kasus terburuk, pendekatan saya yang dimodifikasi memerlukan 4 perbandingan (mungkin bisa menurunkannya menjadi 3 jika saya memeriksa partisi lebih lanjut, meskipun itu terlihat tidak mungkin). Saya sangat ragu bahwa itu akan dikalahkan oleh operasi aritmatika + beban memori (walaupun jika diakses cukup, itu menghilang ke dalam cache CPU). Ingat, pada contoh yang mereka berikan, mereka juga menyembunyikan basis log 2 karena beberapa fungsi IntegerLogBase2 abstrak (yang itu sendiri sebenarnya tidak murah).
Vitali
Sama seperti tindak lanjut, ya jika angka-angkanya terdistribusi normal, melakukan in-order check lebih cepat. Namun, ia memiliki kasus degenerasi dua kali lebih lambat dalam kasus terburuk. Pendekatan yang dipartisi dengan jumlah digit bukannya ruang input berarti bahwa perilaku tidak memiliki kasus yang merosot dan selalu berkinerja optimal. Selanjutnya, ingat Anda membuat asumsi bahwa angka-angka akan didistribusikan secara seragam. Bahkan, mereka lebih cenderung mengikuti beberapa distribusi yang terkait dengan <a href=" en.wikipedia.org/wiki/…> akan menjadi tebakan saya.
Vitali
Peretasan twiddling tidak lebih cepat dari metode partisi di atas, tetapi mereka berpotensi menarik jika Anda memiliki kasus yang lebih umum seperti float di sini.
Corwin Joy
1
Peretasan twiddling menyarankan cara untuk mendapatkan int log10, mengingat int log2. Ini menyarankan beberapa cara untuk mendapatkan int log2, sebagian besar melibatkan beberapa perbandingan / cabang. (Saya pikir Anda meremehkan biaya cabang yang tidak terduga, Vitali). Jika Anda bisa menggunakan inline x86 asm, instruksi BSR akan memberi Anda int log2 dari suatu nilai (yaitu indeks bit dari bit set paling signifikan). Agak lambat pada K8 (10 cycle latency), tetapi cepat pada Core 2 (2 atau 3 cycle latency). Bahkan pada K8, mungkin lebih cepat dari perbandingan.
Peter Cordes
Pada K10, lzcnt menghitung angka nol di depan, jadi hampir sama dengan bsr, tetapi input 0 tidak lagi menjadi kasus khusus dengan hasil yang tidak ditentukan. Latensi: BSR: 4, LZCNT: 2.
Peter Cordes
8

mengkonversi ke string dan kemudian menggunakan fungsi bawaan

unsigned int i;
cout<< to_string(i).length()<<endl;
wugoat
sumber
7
int x = 1000;
int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;
bemaru
sumber
3
Meskipun ini efisien dalam hal LOC, seperti dicatat dalam jawaban yang diterima penggunaan log mungkin tidak akan memberikan kinerja terbaik.
Ian
@Ian Kenapa tidak? Ini hanya beberapa instruksi FPU. Mil lebih baik daripada semua cabang dan loop dalam jawaban lain.
Marquis of Lorne
5

Poster sebelumnya menyarankan loop yang membelah 10. Karena mengalikan pada mesin modern jauh lebih cepat, saya akan merekomendasikan kode berikut sebagai gantinya:

 int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }
Ira Baxter
sumber
1
iblis adalah dalam rincian - apa yang terjadi dengan mengatakan std :: numeric_limits <int> :: sejumlah == max - itu mungkin memiliki masalah terminating
pgast
2
Jika Anda khawatir tentang kasus itu, Anda dapat menambahkan satu IF tambahan untuk menangani nilai yang sangat besar.
Ira Baxter
2
Saya harus mengamati bahwa pada mesin x86, kalikan dengan konstanta 10 seperti yang digunakan dalam kasus ini sebenarnya dapat diimplementasikan oleh kompiler sebagai LEA R2, [8 * R1 + R1], ADD R1, R2 sehingga dibutuhkan 2 jam max. Multiply oleh variabel mengambil puluhan jam, dan membagi jauh lebih buruk.
Ira Baxter
keuntungan dengan pendekatan membagi adalah bahwa Anda tidak perlu khawatir tentang angka negatif.
Johannes Schaub - litb
1
Saya membandingkan pendekatan multiplikasi (dengan fab untuk menghapus masalah tanda) dibandingkan dengan pendekatan divisi. Di mesin saya, pendekatan pembagian adalah faktor 2 lebih lambat dari pendekatan multiplikasi. Apakah ini optimasi prematur atau tidak benar-benar tergantung di mana dan bagaimana ini disebut.
Spacemoose
5

Arsitektur ppc memiliki instruksi penghitungan sedikit. Dengan itu, Anda dapat menentukan basis log 2 dari bilangan bulat positif dalam satu instruksi. Sebagai contoh, 32 bit adalah:

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

Jika Anda dapat menangani margin kesalahan kecil pada nilai besar, Anda dapat mengonversinya menjadi basis 10 dengan beberapa instruksi lain:

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

Ini adalah platform spesifik dan sedikit tidak akurat, tetapi juga tidak melibatkan cabang, divisi, atau konversi ke floating point. Semua tergantung pada apa yang Anda butuhkan.

Saya hanya tahu instruksi ppc begitu saja, tetapi arsitektur lain harus memiliki instruksi serupa.


sumber
Solusi ini menghitung log2 (15) = 4 bit dan log2 (9) = 4 bit. Tetapi 15 dan 9 membutuhkan angka digit desimal yang berbeda untuk dicetak. Jadi itu tidak berhasil, kecuali Anda kadang-kadang tidak keberatan mencetak angka dengan terlalu banyak angka. Tetapi dalam hal ini, Anda selalu dapat memilih "10" sebagai jawaban untuk int.
Ira Baxter
Wow, fungsi perkiraan. Bagus.
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;
 }

Ini mungkin cara paling sederhana untuk menyelesaikan masalah Anda, dengan asumsi Anda hanya peduli pada digit sebelum desimal dan mengasumsikan apa pun yang kurang dari 10 hanya 1 digit.

RoryHector
sumber
1

Saya suka jawaban Ira Baxter. Berikut adalah varian templat yang menangani berbagai ukuran dan penawaran dengan nilai integer maksimum (diperbarui untuk mengerek pemeriksaan batas atas dari loop):

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

Untuk benar-benar mendapatkan peningkatan kinerja dari mengangkat tes tambahan dari loop, Anda perlu mengkhususkan max_decimal () untuk mengembalikan konstanta untuk setiap jenis pada platform Anda. Kompiler ajaib yang cukup dapat mengoptimalkan panggilan ke max_decimal () ke konstan, tetapi spesialisasi lebih baik dengan sebagian besar kompiler saat ini. Seperti berdiri, versi ini mungkin lebih lambat karena biaya max_decimal lebih dari tes yang dihapus dari loop.

Saya akan meninggalkan semua itu sebagai latihan untuk pembaca.

janm
sumber
Anda ingin membuat batas atas memeriksa bersyarat terpisah diuji terlebih dahulu sehingga Anda tidak memeriksanya pada setiap iterasi loop.
Ira Baxter
Anda tidak ingin memasukkan 10 ke dalam temp t itu. Kompilator dapat mempertimbangkan mengalikan dengan t untuk mengalikan dengan variabel nyata, dan menggunakan instruksi perkalian tujuan umum. Jika Anda malah menulis "hasil * = 10;" kompiler pasti akan melihat kalikan dengan konstanta 10 dan mengimplementasikannya dengan beberapa perubahan dan penambahan, yang sangat cepat.
Ira Baxter
Jika perkalian dengan t selalu merupakan perkalian dengan 10, maka ya, kompiler dapat melakukan pengurangan kekuatan. Namun, t bukan loop-invariant dalam kasus ini (itu hanya modifikasi dari fungsi daya integer yang saya miliki di sekitar). Optimasi yang benar adalah spesialisasi pada tipe yang mengembalikan konstanta. Namun, Anda benar bahwa, dalam hal ini, fungsinya selalu menaikkan 10 menjadi daya, bukan bilangan bulat sembarang untuk daya, dan pengurangan kekuatan memberikan kemenangan yang baik. Jadi saya membuat perubahan ... Kali ini perubahan lebih lanjut benar-benar dibiarkan sebagai latihan! (Stack Overflow adalah waktu yang tepat ...)
Januari
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 [email protected]
/// - \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
            )
        )
    );
}
Adolfo
sumber
0

Namun potongan kode lain, yang pada dasarnya sama dengan Vitali tetapi menggunakan pencarian biner. Array Powers malas diinisialisasi sekali per instance tipe yang tidak ditandatangani. Jenis berlebih yang ditandatangani menangani tanda minus.

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

Jika ada yang peduli dengan optimasi lebih lanjut, harap perhatikan bahwa elemen pertama array kekuasaan tidak pernah digunakan, dan lmuncul dengan +12 kali.

Alexey Biryukov
sumber
0

dalam hal jumlah digit DAN nilai setiap posisi digit diperlukan gunakan ini:

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

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

digitmemberi Anda nilai pada posisi nomor yang saat ini diproses dalam loop. misalnya untuk angka 1776 nilai digit adalah:
6 di loop 1
7 di loop 2
7 di loop ke-3
1 di loop ke-4

JFS
sumber
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) );
Adolfo
sumber
Koreksi untuk "Lelucon Praktis" dari 'blinnov.com' di atas
Adolfo
0
/// Determine the number of digits for a 64 bit integer.
/// - Uses at most 5 comparisons.
/// - (cX) 2014 [email protected]
/// - \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
                )
            )
        )
    );
}
Adolfo
sumber
0

untuk integer 'X' Anda ingin tahu jumlah digit, baiklah tanpa menggunakan loop apa pun, solusi ini bertindak dalam satu rumus hanya dalam satu baris jadi ini adalah solusi paling optimal yang pernah saya lihat untuk masalah ini.

 int x = 1000 ; 
 cout<<numberOfDigits = 1+floor(log10(x))<<endl ; 
Sameh Adel
sumber
Gagal untuk INT_MAX dan juga untuk angka negatif.
ranu
@ranu Gagal untuk INT_MAX bagaimana? Kapan argumen dikonversi menjadi double? Atau apakah Anda merujuk ke beberapa input integer yang tidak mungkin dengan angka desimal INT_MAX? Yang juga akan gagal setiap jawaban di sini?
Marquis of Lorne
0
int numberOfDigits(int n){

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

Inilah yang akan saya lakukan, jika Anda menginginkannya untuk basis 10. Cukup cepat dan Anda tidak akan mendapatkan tumpukan overflock penghitungan bilangan bulat

Mc Stevens
sumber
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";
zwi3b3l404
sumber
0

Jika lebih cepat lebih efisien, ini merupakan peningkatan pada perbaikan andrei alexandrescu . Versinya sudah lebih cepat dari cara naif (membaginya dengan 10 pada setiap digit). Versi di bawah ini adalah waktu yang konstan dan lebih cepat setidaknya pada x86-64 dan ARM untuk semua ukuran, tetapi menempati kode biner dua kali lebih banyak, sehingga tidak ramah-cache.

Tolak ukur untuk versi ini vs versi alexandrescu pada PR saya di facebook kebodohan .

Bekerja unsigned, bukan 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);
}
Gabriel
sumber
0

Saya sedang mengerjakan sebuah program yang mengharuskan saya untuk memeriksa apakah pengguna menjawab dengan benar berapa banyak digit dalam suatu angka, jadi saya harus mengembangkan cara untuk memeriksa jumlah digit dalam bilangan bulat. Akhirnya menjadi hal yang relatif mudah dipecahkan.

double check=0, exponent=1000;

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

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

Ini akhirnya menjadi jawaban saya yang saat ini bekerja dengan angka dengan kurang dari 10 ^ 1000 digit (dapat diubah dengan mengubah nilai eksponen).

PS Saya tahu jawaban ini terlambat sepuluh tahun tetapi saya tiba di sini pada tahun 2020 sehingga orang lain mungkin menggunakannya.

Daniel Bercero
sumber
-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);
    }
};

di mana powers_and_maxkita miliki (10^n)-1untuk semua nitu

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

dan std::numeric_limits<type>::max()dalam sebuah array:

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

inilah tes sederhana:

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

Tentu saja implementasi lain dari himpunan yang diperintahkan mungkin digunakan untuk powers_and_maxdan jika ada pengetahuan bahwa akan ada pengelompokan tetapi tidak ada pengetahuan tentang di mana kluster itu mungkin implementasi pohon penyesuaian diri mungkin yang terbaik

pgast
sumber
-1

cara yang efektif

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;
}
Davit Siradeghyan
sumber
-1

Pembaruan C ++ 11 dari solusi yang disukai:

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

mencegah instantiasi template dengan double, et. Al.

gerardw
sumber
-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;
}
DPenner1
sumber
-2

Inilah cara saya untuk melakukan itu:

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

        return count;
    }
Leonardo Urbano
sumber
2
while true / break syndrome: D
Петър Петров
-1 ini adalah pendekatan yang sama dengan jawaban pertama yang diberikan enam tahun sebelumnya, dan tidak menambahkan apa-apa (sebenarnya jauh lebih buruk).
-4

Berikut pendekatan yang berbeda:

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

Ini mungkin tidak efisien, hanya sesuatu yang berbeda dari yang disarankan orang lain.

Ashwin
sumber
4
Permintaan itu sangat efisien. Ini kebalikannya.
Ira Baxter