1. Pengenalan
Dalam tutorial ringkas ini, kita akan meneroka pelbagai cara mendapatkan bilangan digit dalam Integer di Java.
Kami juga akan menganalisis kaedah yang berbeza dan akan mengetahui algoritma mana yang paling sesuai dengan situasi kami.
2. Bilangan Digit dalam Integer
Untuk kaedah yang dibincangkan di sini, kami hanya mempertimbangkan bilangan bulat positif. Sekiranya kita menjangkakan adanya input negatif, maka kita dapat menggunakan Math.abs (number) terlebih dahulu sebelum menggunakan kaedah ini.
2.1. Penyelesaian Berasaskan String
Mungkin cara termudah untuk mendapatkan bilangan digit dalam Integer adalah dengan menukarnya menjadi String , dan memanggil kaedah panjang () . Ini akan mengembalikan panjang perwakilan String bagi nombor kami:
int length = String.valueOf(number).length();
Tetapi, ini mungkin pendekatan yang tidak optimum, kerana pernyataan ini melibatkan peruntukan memori untuk String, untuk setiap penilaian . JVM mesti menguraikan nombor kami terlebih dahulu dan menyalin digitnya ke dalam String yang berasingan dan melakukan sejumlah operasi yang berbeza juga (seperti menyimpan salinan sementara, menangani penukaran Unicode dll).
Sekiranya kita hanya mempunyai beberapa nombor untuk dinilai, maka kita dapat dengan jelas menggunakan penyelesaian ini - kerana perbezaan antara ini dan pendekatan lain akan dapat diabaikan walaupun untuk jumlah yang besar.
2.2. Pendekatan Logaritma
Untuk nombor yang ditunjukkan dalam bentuk perpuluhan, jika kita mengambil log log mereka 10 dan membulatkannya maka kita akan mendapat bilangan digit dalam nombor itu:
int length = (int) (Math.log10(number) + 1);
Perhatikan bahawa log 10 0 sebarang nombor tidak ditentukan. Oleh itu, jika kita mengharapkan input dengan nilai 0 , maka kita juga boleh mengeceknya.
Pendekatan logaritma jauh lebih cepat daripada pendekatan berasaskan String kerana tidak perlu melalui proses penukaran data. Ia hanya melibatkan pengiraan sederhana dan mudah tanpa inisialisasi objek tambahan atau gelung.
2.3. Pendaraban Berulang
Dalam kaedah ini, kita akan mengambil pemboleh ubah sementara (diinisialisasi menjadi 1) dan akan terus menggandakannya dengan 10 hingga menjadi lebih besar kepada bilangan kita. Semasa proses ini, kami juga akan menggunakan pemboleh ubah panjang yang akan menjejaki panjang nombor:
int length = 0; long temp = 1; while (temp <= number) { length++; temp *= 10; } return length;
Dalam kod ini, garis temp * = 10 sama dengan menulis temp = (temp << 3) + (temp << 1) . Oleh kerana pendaraban biasanya merupakan operasi yang lebih mahal pada beberapa pemproses jika dibandingkan dengan operator shift, yang terakhir mungkin sedikit lebih efisien.
2.4. Membahagi Dengan Kekuatan Dua
Sekiranya kita mengetahui tentang julat bilangan kita, maka kita dapat menggunakan variasi yang akan lebih mengurangkan perbandingan kita. Kaedah ini membahagi bilangan dengan kuasa dua (mis. 1, 2, 4, 8 dll):
Kaedah ini membahagi bilangan dengan kuasa dua (mis. 1, 2, 4, 8 dll):
int length = 1; if (number >= 100000000) { length += 8; number /= 100000000; } if (number >= 10000) { length += 4; number /= 10000; } if (number >= 100) { length += 2; number /= 100; } if (number >= 10) { length += 1; } return length;
Ini memanfaatkan fakta bahawa nombor apa pun dapat ditunjukkan dengan penambahan kuasa 2. Sebagai contoh, 15 dapat diwakili sebagai 8 + 4 + 2 + 1, yang semuanya adalah kekuatan 2.
Untuk nombor 15 digit, kami akan melakukan 15 perbandingan dalam pendekatan kami sebelumnya, yang kami telah mengurangkan menjadi hanya 4 dalam kaedah ini.
2.5. Pecah dan perintah
Ini mungkin merupakan pendekatan paling besar jika dibandingkan dengan yang lain yang dijelaskan di sini, tetapi tidak perlu dikatakan, ini adalah yang terpantas kerana kami tidak melakukan jenis penukaran, pendaraban, penambahan atau inisialisasi objek.
Kami mendapat jawapan kami hanya dalam tiga atau empat sederhana jika pernyataan:
if (number < 100000) { if (number < 100) { if (number < 10) { return 1; } else { return 2; } } else { if (number < 1000) { return 3; } else { if (number < 10000) { return 4; } else { return 5; } } } } else { if (number < 10000000) { if (number < 1000000) { return 6; } else { return 7; } } else { if (number < 100000000) { return 8; } else { if (number < 1000000000) { return 9; } else { return 10; } } } }
Sama seperti pendekatan sebelumnya, kita boleh menggunakan kaedah ini hanya jika kita mengetahui tentang julat nombor kita.
3. Penandaarasan
Sekarang kita mempunyai pemahaman yang baik mengenai penyelesaian yang berpotensi, sekarang mari kita membuat penanda aras mudah semua kaedah kami menggunakan Java Microbenchmark Harness (JMH).
Jadual berikut menunjukkan purata masa pemprosesan setiap operasi (dalam nanodetik):
Benchmark Mode Cnt Score Error Units Benchmarking.stringBasedSolution avgt 200 32.736 ± 0.589 ns/op Benchmarking.logarithmicApproach avgt 200 26.123 ± 0.064 ns/op Benchmarking.repeatedMultiplication avgt 200 7.494 ± 0.207 ns/op Benchmarking.dividingWithPowersOf2 avgt 200 1.264 ± 0.030 ns/op Benchmarking.divideAndConquer avgt 200 0.956 ± 0.011 ns/op
The String berasaskan penyelesaian, yang adalah yang paling mudah, juga operasi yang paling mahal - kerana ini adalah satu-satunya yang memerlukan penukaran data dan pengawalan objek baru.
Pendekatan logaritma jauh lebih efisien, berbanding dengan penyelesaian sebelumnya - kerana tidak melibatkan penukaran data. Dan, sebagai penyelesaian satu baris, ia boleh menjadi alternatif yang baik untuk pendekatan berasaskan String .
Pendaraban berulang melibatkan pendaraban sederhana, berkadar dengan panjang nombor; sebagai contoh, jika nombor panjangnya lima belas digit, maka kaedah ini akan melibatkan lima belas pendaraban.
Walau bagaimanapun, kaedah seterusnya memanfaatkan fakta bahawa setiap nombor dapat diwakili oleh kekuatan dua (pendekatan yang serupa dengan BCD), dan mengurangkan yang sama kepada 4 operasi pembahagian, jadi lebih efisien daripada yang sebelumnya.
Akhirnya, seperti yang dapat kita simpulkan, algoritma yang paling cekap adalah pelaksanaan Divide and Conquer secara verbose - yang memberikan jawapan hanya dalam tiga atau empat pernyataan sederhana sekiranya. Kita boleh menggunakannya jika kita mempunyai set data yang besar yang perlu kita analisis.
4. Kesimpulan
Dalam artikel ringkas ini, kami menggariskan beberapa cara untuk mencari bilangan digit dalam bilangan bulat dan kami membandingkan kecekapan setiap pendekatan.
Dan, seperti biasa, anda boleh mendapatkan kod lengkap di GitHub.