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 solutiontemplate<class T>int numDigits(T number){int digits =0;if(number <0) digits =1;// remove this line if '-' counts as a digitwhile(number){
number /=10;
digits++;}return digits;}// partial specialization optimization for 32-bit numberstemplate<>int numDigits(int32_t x){if(x == MIN_INT)return10+1;if(x <0)return numDigits(-x)+1;if(x >=10000){if(x >=10000000){if(x >=100000000){if(x >=1000000000)return10;return9;}return8;}if(x >=100000){if(x >=1000000)return7;return6;}return5;}if(x >=100){if(x >=1000)return4;return3;}if(x >=10)return2;return1;}// partial-specialization optimization for 8-bit numberstemplate<>int numDigits(char n){// if you have the time, replace this with a static initialization to avoid// the initial overhead & unnecessary branchstaticchar 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];}
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:
unsignedGetNumberOfDigits(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.
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?
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<unsignedlonglong 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.
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.
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
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;}
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:
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.
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>usingnamespace 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;return0;}
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.
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.
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
*/unsignedNumDigits32bs(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)));}
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_tNumberOfDecPositions( 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_tNumberOfDecPositions( T v,typename std::enable_if<std::is_signed<T>::value>::type*=0){typedeftypename std::make_unsigned<T>::type unsigned_type;if( v <0)returnNumberOfDecPositions(static_cast<unsigned_type>(-v))+1;elsereturnNumberOfDecPositions(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.
dalam hal jumlah digit DAN nilai setiap posisi digit diperlukan gunakan ini:
int64_t= number, digitValue, digits =0;// or "int" for 32bitwhile(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
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 ;
@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){return1;}return1+ 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
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";
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.
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.
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
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;}
-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 arrayif(num <0)
digits--;
Ini mungkin tidak efisien, hanya sesuatu yang berbeda dari yang disarankan orang lain.
Jawaban:
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.
sumber
Cara paling sederhana adalah dengan melakukan:
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.sumber
-fpfast
Anda bisa melihat penggunaan instrinsik SSE daripada x87, yang menghasilkan lebih sedikit jaminan pada presisi IIRC. tetapi secara default tidak ada masalah.Mungkin saya salah paham pertanyaannya tetapi tidakkah ini berhasil?
sumber
Catatan: "0" akan memiliki 0 digit! Jika Anda perlu 0 untuk memiliki 1 digit, gunakan:
(Terima kasih Kevin Fegan)
Pada akhirnya, gunakan profiler untuk mengetahui mana dari semua jawaban di sini yang akan lebih cepat di mesin Anda ...
sumber
Lelucon praktis: Ini adalah cara yang paling efisien (jumlah digit dihitung pada waktu kompilasi):
Mungkin bermanfaat untuk menentukan lebar yang diperlukan untuk bidang angka dalam pemformatan, elemen input dll.
sumber
0
dan juga gagal pada basis1
:) dan memberikan bagi dengan kesalahan nol jika basis diberikan sebagai0
. 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.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.sumber
mengkonversi ke string dan kemudian menggunakan fungsi bawaan
sumber
sumber
Poster sebelumnya menyarankan loop yang membelah 10. Karena mengalikan pada mesin modern jauh lebih cepat, saya akan merekomendasikan kode berikut sebagai gantinya:
sumber
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:
Jika Anda dapat menangani margin kesalahan kecil pada nilai besar, Anda dapat mengonversinya menjadi basis 10 dengan beberapa instruksi lain:
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
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.
sumber
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):
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.
sumber
sumber
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.
Jika ada yang peduli dengan optimasi lebih lanjut, harap perhatikan bahwa elemen pertama array kekuasaan tidak pernah digunakan, dan
l
muncul dengan+1
2 kali.sumber
dalam hal jumlah digit DAN nilai setiap posisi digit diperlukan gunakan ini:
digit
memberi 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
sumber
sumber
sumber
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.
sumber
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?Inilah yang akan saya lakukan, jika Anda menginginkannya untuk basis 10. Cukup cepat dan Anda tidak akan mendapatkan tumpukan overflock penghitungan bilangan bulat
sumber
sumber
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
, bukansigned
.sumber
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.
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.
sumber
di mana
powers_and_max
kita miliki(10^n)-1
untuk semuan
itu(10^n) <
std::numeric_limits<type>::max()
dan
std::numeric_limits<type>::max()
dalam sebuah array:inilah tes sederhana:
Tentu saja implementasi lain dari himpunan yang diperintahkan mungkin digunakan untuk
powers_and_max
dan jika ada pengetahuan bahwa akan ada pengelompokan tetapi tidak ada pengetahuan tentang di mana kluster itu mungkin implementasi pohon penyesuaian diri mungkin yang terbaiksumber
cara yang efektif
sumber
Pembaruan C ++ 11 dari solusi yang disukai:
mencegah instantiasi template dengan double, et. Al.
sumber
sumber
Inilah cara saya untuk melakukan itu:
sumber
Berikut pendekatan yang berbeda:
Ini mungkin tidak efisien, hanya sesuatu yang berbeda dari yang disarankan orang lain.
sumber