Cara mendapatkan jumlah digit dalam int?

386

Apakah ada cara yang lebih rapi untuk mendapatkan panjang int daripada metode ini?

int length = String.valueOf(1000).length();
pertama
sumber
7
tolong tentukan panjang int.
Tom
24
Saya pikir dia ingin menghitung angka dalam angka.
Alberto Zaccagni
3
Jawaban yang diberikan orang kepada Anda benar ... mereka memberi Anda panjang int tanpa mengubahnya menjadi string ... tapi mengapa Anda tidak ingin mengubahnya menjadi string? Apakah ini hal yang cepat? Jika demikian, saya tidak yakin bahwa metode ini akan lebih cepat ... Anda mungkin ingin melakukan beberapa tes (atau memutuskan apakah itu penting).
Beska
3
Digit @ptomli hexadecimal masih digit, hanya di sistem basis yang berbeda.
Mark Pim
2
@ Patomli Tentu, tetapi keduanya dalam fungsi Integer.toString, dan dalam percakapan umum, desimal adalah default. Ketika bank memberi tahu saya, "Tuliskan jumlah cek Anda di kotak ini", saya tidak bertanya kepada mereka apakah saya harus menuliskannya dalam desimal, hex, atau oktal. Kami menganggap desimal kecuali ditentukan atau dipanggil oleh konteks.
Jay

Jawaban:

349

Solusi berbasis String Anda benar-benar oke, tidak ada yang "tidak rapi" tentangnya. Anda harus menyadari bahwa secara matematis, angka tidak memiliki panjang, juga angka. Panjang dan digit sama-sama properti dari representasi fisik angka dalam basis tertentu, yaitu String.

Solusi berbasis logaritma melakukan (beberapa) hal-hal yang sama dengan yang berbasis string secara internal, dan mungkin melakukannya (tidak signifikan) lebih cepat karena hanya menghasilkan panjang dan mengabaikan angka. Tetapi saya tidak akan benar-benar mempertimbangkannya dengan maksud yang lebih jelas - dan itulah faktor terpenting.

Michael Borgwardt
sumber
54
1 untuk mempertimbangkan niat kode ketika memilih cara untuk memecahkan masalah
pupeno
5
Datapoint: Di mesin saya, metode log tampaknya berjalan di bawah dua kali lebih cepat dari metode panjang string. Saya tidak akan menyebut itu tidak penting jika metode dipanggil banyak atau dalam bagian kode waktu-kritis.
CPerkins
1
Lihat unit test benchmark saya di bawah ini (yang mungkin juga cacat saya bukan ahli benchmark). Lebih dari sejumlah besar berjalan (100.000), kecepatan 11s sampai 8s pada mesin saya hampir tidak dua kali lebih cepat.
Jean
5
@CPerkins. Optimalisasi prematur. Anda tahu omongan itu.
Michael Borgwardt
11
Beberapa tambahan (sangat terlambat): Ini mungkin tidak berfungsi dengan baik untuk nilai negatif, tergantung jika Anda mengharapkan "-" menjadi digit atau tidak. Menambahkan Math.abs()akan memperbaiki ini, meskipun.
YingYang
265

Logaritma adalah teman Anda:

int n = 1000;
int length = (int)(Math.log10(n)+1);

NB: hanya valid untuk n> 0.

Dmitry Brant
sumber
2
Dan apakah ini lebih cepat atau lebih baik daripada menggunakan varian saya?
fnst
+1 Anda mengalahkan saya sebentar, dan jawaban Anda benar, di mana jawaban saya sedikit salah. Perhatikan, bagaimanapun, bahwa kompiler akan mengeluh karena pemain hilang ke int
Dirk
2
@ Tom Mengapa Anda menganggap itu mahal? Orang mungkin berasumsi bahwa co-prosesor matematika akan mengeksekusinya, sehingga mungkin mendekati kecepatan penambahan. Bahkan jika java tidak menggunakan co-prosesor sekarang, itu asumsi yang baik bahwa itu mungkin ... (Kami hanya akan mengabaikan implikasi Anda yang bahkan lebih tidak berpendidikan bahwa Java lambat karena Anda mungkin tidak tertarik pada bukti - atau jika Anda, Anda akan pergi ke shootout.alioth.debian.org dan mencari tahu sendiri)
Bill K
8
Berfungsi ... kecuali nilai yang Anda periksa = 0, yang akan memberi Anda hasil aneh (-2147483647). Math.log10 API: "Jika argumennya positif nol atau nol negatif, maka hasilnya adalah infinity negatif."
mujimu
2
+1 Menyajikan metode yang tidak melibatkan alokasi memori objek, yang merupakan keharusan untuk memaksimalkan penggunaan kembali untuk menghindari koleksi GC.
Michael Wojcik
159

Pendekatan tercepat: bagilah dan taklukkan.

Dengan asumsi rentang Anda adalah 0 hingga MAX_INT, maka Anda memiliki 1 hingga 10 digit. Anda dapat mendekati interval ini menggunakan membagi dan menaklukkan, dengan hingga 4 perbandingan per setiap input. Pertama, Anda membagi [1..10] menjadi [1..5] dan [6..10] dengan satu perbandingan, dan kemudian setiap interval 5 panjang yang Anda bagi menggunakan satu perbandingan menjadi satu interval 3 dan satu panjang 2. Interval panjang 2 membutuhkan satu perbandingan lagi (total 3 perbandingan), interval panjang 3 dapat dibagi menjadi interval panjang 1 (solusi) dan interval panjang 2. Jadi, Anda perlu 3 atau 4 perbandingan.

Tidak ada divisi, tidak ada operasi floating point, tidak ada logaritma mahal, hanya perbandingan integer.

Kode (panjang tapi cepat):

if (n < 100000){
        // 5 or less
        if (n < 100){
            // 1 or 2
            if (n < 10)
                return 1;
            else
                return 2;
        }else{
            // 3 or 4 or 5
            if (n < 1000)
                return 3;
            else{
                // 4 or 5
                if (n < 10000)
                    return 4;
                else
                    return 5;
            }
        }
    } else {
        // 6 or more
        if (n < 10000000) {
            // 6 or 7
            if (n < 1000000)
                return 6;
            else
                return 7;
        } else {
            // 8 to 10
            if (n < 100000000)
                return 8;
            else {
                // 9 or 10
                if (n < 1000000000)
                    return 9;
                else
                    return 10;
            }
        }
    }

Benchmark (setelah pemanasan JVM) - lihat kode di bawah ini untuk melihat bagaimana benchmark dijalankan:

  1. metode dasar (dengan String.length): 2145ms
  2. metode log10: 711ms = 3.02 kali lebih cepat dari baseline
  3. pembagian berulang: 2797 ms = 0,77 kali lebih cepat dari baseline
  4. Divide-and-Conquer: 74ms = 28,99
    kali lebih cepat dari baseline

Kode lengkap:

public static void main(String[] args)
throws Exception
{

    // validate methods:
    for (int i = 0; i < 1000; i++)
        if (method1(i) != method2(i))
            System.out.println(i);
    for (int i = 0; i < 1000; i++)
        if (method1(i) != method3(i))
            System.out.println(i + " " + method1(i) + " " + method3(i));
    for (int i = 333; i < 2000000000; i += 1000)
        if (method1(i) != method3(i))
            System.out.println(i + " " + method1(i) + " " + method3(i));
    for (int i = 0; i < 1000; i++)
        if (method1(i) != method4(i))
            System.out.println(i + " " + method1(i) + " " + method4(i));
    for (int i = 333; i < 2000000000; i += 1000)
        if (method1(i) != method4(i))
            System.out.println(i + " " + method1(i) + " " + method4(i));

    // work-up the JVM - make sure everything will be run in hot-spot mode
    allMethod1();
    allMethod2();
    allMethod3();
    allMethod4();

    // run benchmark
    Chronometer c;

    c = new Chronometer(true);
    allMethod1();
    c.stop();
    long baseline = c.getValue();
    System.out.println(c);

    c = new Chronometer(true);
    allMethod2();
    c.stop();
    System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");

    c = new Chronometer(true);
    allMethod3();
    c.stop();
    System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");

    c = new Chronometer(true);
    allMethod4();
    c.stop();
    System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");
}


private static int method1(int n)
{
    return Integer.toString(n).length();
}
private static int method2(int n)
{
    if (n == 0)
        return 1;
    return (int)(Math.log10(n) + 1);
}
private static int method3(int n)
{
    if (n == 0)
        return 1;
    int l;
    for (l = 0 ; n > 0 ;++l)
        n /= 10;
    return l;
}
private static int method4(int n)
{
    if (n < 100000)
    {
        // 5 or less
        if (n < 100)
        {
            // 1 or 2
            if (n < 10)
                return 1;
            else
                return 2;
        }
        else
        {
            // 3 or 4 or 5
            if (n < 1000)
                return 3;
            else
            {
                // 4 or 5
                if (n < 10000)
                    return 4;
                else
                    return 5;
            }
        }
    }
    else
    {
        // 6 or more
        if (n < 10000000)
        {
            // 6 or 7
            if (n < 1000000)
                return 6;
            else
                return 7;
        }
        else
        {
            // 8 to 10
            if (n < 100000000)
                return 8;
            else
            {
                // 9 or 10
                if (n < 1000000000)
                    return 9;
                else
                    return 10;
            }
        }
    }
}


private static int allMethod1()
{
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method1(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method1(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method1(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method1(i);

    return x;
}
private static int allMethod2()
{
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method2(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method2(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method2(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method2(i);

    return x;
}
private static int allMethod3()
{
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method3(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method3(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method3(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method3(i);

    return x;
}
private static int allMethod4()
{
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method4(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method4(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method4(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method4(i);

    return x;
}

Sekali lagi, patokan:

  1. metode dasar (dengan String.length): 2145ms
  2. metode log10: 711ms = 3.02 kali lebih cepat dari baseline
  3. pembagian berulang: 2797 ms = 0,77 kali lebih cepat dari baseline
  4. Divide-and-Conquer: 74ms = 28,99
    kali lebih cepat dari baseline

Sunting: Setelah saya menulis patokan, saya menyelinap ke Integer.toString dari Java 6, dan saya menemukan bahwa ia menggunakan:

final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                  99999999, 999999999, Integer.MAX_VALUE };

// Requires positive x
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}

Saya membandingkannya dengan solusi divide-and-conquer saya:

  1. membagi-dan-taklukkan: 104ms
  2. Solusi Java 6 - iterate dan bandingkan: 406ms

Tambang saya sekitar 4x lebih cepat dari solusi Java 6.

Marian
sumber
7
ini terlihat hebat. Anda bisa menulisnya sedikit lebih kompak menggunakan operator?: untuk mendapatkan lebih banyak penerimaan
André Pareis
88
berbicara tentang pengoptimalan prematur: D
Gordon Gustafson
2
Saya suka itu! Bagaimana dengan blok switch alih-alih bersarang jika-elses?
Kebman
2
Saya tidak menyadari semua ini jika pernyataan lain akan jauh lebih cepat daripada mengubah int ke String lalu memanggil .length. +1
Ogen
15
Menggunakan operator ternary, membawanya ke 101 karakter:n<100000?n<100?n<10?1:2:n<1000?3:n<10000?4:5:n<10000000?n<1000000?6:7:n<100000000?8:n<1000000000?9:10
Jonathan Gawrych
13

Dua komentar tentang tolok ukur Anda: Java adalah lingkungan yang kompleks, apa dengan kompilasi just-in-time dan pengumpulan sampah dan sebagainya, sehingga untuk mendapatkan perbandingan yang adil, setiap kali saya menjalankan tolok ukur, saya selalu: (a) melampirkan dua tes dalam satu loop yang menjalankannya secara berurutan 5 atau 10 kali. Cukup sering runtime pada pass kedua melalui loop sangat berbeda dari yang pertama. Dan (b) Setelah setiap "pendekatan", saya melakukan System.gc () untuk mencoba memicu pengumpulan sampah. Kalau tidak, pendekatan pertama mungkin menghasilkan banyak objek, tetapi tidak cukup untuk memaksa pengumpulan sampah, maka pendekatan kedua menciptakan beberapa objek, tumpukan habis, dan pengumpulan sampah berjalan. Kemudian pendekatan kedua "dibebankan" untuk mengambil sampah yang ditinggalkan oleh pendekatan pertama. Sangat tidak adil!

Yang mengatakan, tak satu pun di atas membuat perbedaan yang signifikan dalam contoh ini.

Dengan atau tanpa modifikasi itu, saya mendapat hasil yang sangat berbeda dari yang Anda lakukan. Ketika saya menjalankan ini, ya, pendekatan toString memberikan waktu berjalan dari 6400 hingga 6600 milis, sedangkan pendekatan log topok 20.000 hingga 20.400 milis. Alih-alih sedikit lebih cepat, pendekatan log 3 kali lebih lambat bagi saya.

Perhatikan bahwa kedua pendekatan ini melibatkan biaya yang sangat berbeda, jadi ini tidak terlalu mengejutkan: Pendekatan toString akan menciptakan banyak objek sementara yang harus dibersihkan, sementara pendekatan log membutuhkan perhitungan yang lebih intens. Jadi mungkin perbedaannya adalah bahwa pada mesin dengan memori lebih sedikit, toString membutuhkan lebih banyak putaran pengumpulan sampah, sedangkan pada mesin dengan prosesor yang lebih lambat, perhitungan ekstra dari log akan lebih menyakitkan.

Saya juga mencoba pendekatan ketiga. Saya menulis fungsi kecil ini:

static int numlength(int n)
{
    if (n == 0) return 1;
    int l;
    n=Math.abs(n);
    for (l=0;n>0;++l)
        n/=10;
    return l;           
}

Itu berjalan pada 1600 hingga 1900 milis - kurang dari 1/3 pendekatan toString, dan 1/10 pendekatan log pada mesin saya.

Jika Anda memiliki rentang angka yang luas, Anda bisa mempercepatnya lebih jauh dengan mulai membagi dengan 1.000 atau 1.000.000 untuk mengurangi jumlah kali melalui loop. Saya belum bermain dengan itu.

Jay
sumber
Sudahkah Anda mencoba memvariasikan input? VM hotspot dapat mengoptimalkan grafik ini jika tidak, menghasilkan tolok ukur yang salah, karena ia mengembalikan hal yang sama yang telah dihitung sebelumnya.
Erik Aigner
11

Menggunakan Java

int nDigits = Math.floor(Math.log10(Math.abs(the_integer))) + 1;

gunakan import java.lang.Math.*;di awal

Menggunakan C

int nDigits = floor(log10(abs(the_integer))) + 1;

gunakan inclue math.hdi awal

Santosh
sumber
1
Untuk diketahui, akan mengakibatkan tak terhingga jika the_integerini 0, jadi untuk itu.
Erik Aigner
10

Tidak dapat meninggalkan komentar, jadi saya akan memposting sebagai jawaban terpisah.

Solusi berbasis logaritma tidak menghitung jumlah digit yang benar untuk bilangan bulat yang sangat besar, misalnya:

long n = 99999999999999999L;

// correct answer: 17
int numberOfDigits = String.valueOf(n).length();

// incorrect answer: 18
int wrongNumberOfDigits = (int) (Math.log10(n) + 1); 

Solusi berbasis logaritma menghitung jumlah digit yang tidak benar dalam bilangan bulat besar

moodcheerful
sumber
coba (int) (Math.log10 (n + j)) sebagai gantinya j adalah 10 - (n - n / 10 * 10).
Erick Stone
8

Karena jumlah digit dalam basis 10 integer hanya 1 + truncate (log10 (angka)) , Anda dapat melakukan:

public class Test {

    public static void main(String[] args) {

        final int number = 1234;
        final int digits = 1 + (int)Math.floor(Math.log10(number));

        System.out.println(digits);
    }
}

Diedit karena edit terakhir saya memperbaiki contoh kode, tetapi bukan deskripsi.

Beladau
sumber
Keren. tapi saya pikir itu perlu abs (angka) dan juga "0" adalah case khusus juga?
DmitryK
Iya. Jika Anda perlu memperhitungkan tanda, Anda harus melakukan sesuatu seperti 1 + (int) Math.floor (Math.log10 (Math.abs (angka))) + + ((angka <0)? 1: 0)
Dirk
5
Ini Math.flooragak berlebihan, bukan? Tetap intakan membulatkannya ke bawah.
CompuChip
5

Solusi Marian disesuaikan untuk nomor tipe lama (hingga 9.223.372.036.854.775.807), jika seseorang ingin menyalin & menempelkannya. Dalam program saya menulis ini untuk angka hingga 10.000 jauh lebih mungkin, jadi saya membuat cabang khusus untuk mereka. Pokoknya itu tidak akan membuat perbedaan yang signifikan.

public static int numberOfDigits (long n) {     
    // Guessing 4 digit numbers will be more probable.
    // They are set in the first branch.
    if (n < 10000L) { // from 1 to 4
        if (n < 100L) { // 1 or 2
            if (n < 10L) {
                return 1;
            } else {
                return 2;
            }
        } else { // 3 or 4
            if (n < 1000L) {
                return 3;
            } else {
                return 4;
            }
        }           
    } else  { // from 5 a 20 (albeit longs can't have more than 18 or 19)
        if (n < 1000000000000L) { // from 5 to 12
            if (n < 100000000L) { // from 5 to 8
                if (n < 1000000L) { // 5 or 6
                    if (n < 100000L) {
                        return 5;
                    } else {
                        return 6;
                    }
                } else { // 7 u 8
                    if (n < 10000000L) {
                        return 7;
                    } else {
                        return 8;
                    }
                }
            } else { // from 9 to 12
                if (n < 10000000000L) { // 9 or 10
                    if (n < 1000000000L) {
                        return 9;
                    } else {
                        return 10;
                    }
                } else { // 11 or 12
                    if (n < 100000000000L) {
                        return 11;
                    } else {
                        return 12;
                    }
                }
            }
        } else { // from 13 to ... (18 or 20)
            if (n < 10000000000000000L) { // from 13 to 16
                if (n < 100000000000000L) { // 13 or 14
                    if (n < 10000000000000L) { 
                        return 13;
                    } else {
                        return 14;
                    }
                } else { // 15 or 16
                    if (n < 1000000000000000L) {
                        return 15;
                    } else {
                        return 16;
                    }
                }
            } else { // from 17 to ...¿20?
                if (n < 1000000000000000000L) { // 17 or 18
                    if (n < 100000000000000000L) {
                        return 17;
                    } else {
                        return 18;
                    }
                } else { // 19? Can it be?
                    // 10000000000000000000L is'nt a valid long.
                    return 19;
                }
            }
        }
    }
}
PENJARA
sumber
Haruskah judul pertanyaan ini diubah menjadi "Cara untuk mendapatkan jumlah digit dalam int / long?" (dan menambahkan tag 'panjang')
JAIL
4

Pendekatan string lain. Pendek dan manis - untuk bilangan bulat apa pun n.

int length = ("" + n).length();
Klik ini
sumber
Hanya berfungsi untuk bilangan bulat positif ndan nol. Dapat digunakan ("" + Math.abs(n)).length()untuk mendapatkan panjang bilangan bulat negatif.
ThisClark
3

Bisakah saya mencoba? ;)

berdasarkan solusi Dirk

final int digits = number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number))));
DmitryK
sumber
3

Bagaimana dengan Matematika kuno? Bagi dengan 10 hingga Anda mencapai 0.

public static int getSize(long number) {
        int count = 0;
        while (number > 0) {
            count += 1;
            number = (number / 10);
        }
        return count;
    }
Sinista
sumber
1
Sudahkah Anda mengujinya? Anda tahu, meski sulit, bagi sudut pandang manusia, itu tidak benar-benar bekerja sama dengan "cara berpikir" mesin, kan? --- Mari saya usulkan satu hal: Buatlah array dua juta angka, lebih disukai Long.MAX_VALUE, yang merupakan kasus kompleksitas terburuk kode Anda, dan gunakan System.nanoTime()untuk melakukan uji coba pencatatan jam kerja terhadap kasus kompleksitas terburuk dari solusi lain. ++ Sebenarnya, cobalah dengan array diisi oleh satu set randomizer untuk kisaran 0untuk Long.MAX_VALUEjuga, hanya untuk "rata-rata kompleksitas" menguji ++ Anda mungkin menemukan hasil ... sangat mengejutkan.
XenoRo
@ thelima Ini tidak berfungsi dengan benar untuk nol atau negatif, tapi itu bug kecil. Prinsipnya terlihat benar bagi saya. Apa hasil "mengejutkan" yang Anda maksud?
Jay
Anggap saja komputer ... Ya ... Mereka tidak suka membagi. Dan dalam kasus-kasus di mana "antrian" besar dalam jumlah besar perlu diproses, dan setiap digit di setiap nomor yang diproses akan membutuhkan pembagian ... Ya ... Hal-hal "mulai menjadi sangat lambat sangat cepat" ... Jika Anda menangkap artinya ... --- Inilah sebabnya mengapa Anda melihat banyak jawaban di sini menggunakan kode berdasarkan tes dan perbandingan dengan setiap angka desimal menggunakan 'jika, daripada pembagian: Jika tidak lebih cepat, setidaknya itu mempertahankan sebagian besar kecepatan itu terlepas itu kasus terburuk. --- Lakukan tes antara menggunakan divisi dan logaritma dalam jumlah besar ...
XenoRo
@ Theima apa yang kamu bicarakan? Untuk int,loop ini dieksekusi maksimal 11 kali. Apakah Anda memiliki beberapa bukti untuk pernyataan Anda?
Marquis of Lorne
@ EJP Dari sudut pandang perangkat keras, pembagian adalah proses berulang. Algoritma pembagian tercepat yang saya tahu adalah radix4, yang menghasilkan 4 bit per iterasi; jadi membagi 32 bit membutuhkan 8 iterasi setidaknya. Perkalian, misalnya, dapat dilakukan secara paralel, dan juga dapat dipecah menjadi perkalian yang lebih sederhana; baik turun ke tingkat bit (hanya membutuhkan 5 operasi), atau dengan kerusakan sebagian ditambah tabel pencarian di akhir (ukuran klasik VS kecepatan trade-off). Ini bukan hanya tentang "berapa banyak iterasi"; masalah dengan divisi terletak pada "apa yang disiratkan / dilakukan setiap iterasi, pada tingkat perangkat keras"
XenoRo
2

Solusi Marian, sekarang dengan Ternary:

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

Karena kita bisa.

Pengguna tidak ditemukan
sumber
2
Itu agak sulit dibaca. Mungkin menambahkan beberapa spasi dan / atau baris baru.
michaelb958 - GoFundMonica
Tapi sialnya itu portabel!
Trevor Rudolph
1

Penasaran, saya mencoba membandingkannya ...

import org.junit.Test;
import static org.junit.Assert.*;


public class TestStack1306727 {

    @Test
    public void bench(){
        int number=1000;
        int a= String.valueOf(number).length();
        int b= 1 + (int)Math.floor(Math.log10(number));

        assertEquals(a,b);
        int i=0;
        int s=0;
        long startTime = System.currentTimeMillis();
        for(i=0, s=0; i< 100000000; i++){
            a= String.valueOf(number).length();
            s+=a;
        }
        long stopTime = System.currentTimeMillis();
        long runTime = stopTime - startTime;
        System.out.println("Run time 1: " + runTime);
        System.out.println("s: "+s);
        startTime = System.currentTimeMillis();
        for(i=0,s=0; i< 100000000; i++){
            b= number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number))));
            s+=b;
        }
        stopTime = System.currentTimeMillis();
        runTime = stopTime - startTime;
        System.out.println("Run time 2: " + runTime);
        System.out.println("s: "+s);
        assertEquals(a,b);


    }
}

hasilnya adalah:

Jalankan waktu 1: 6765
s: 400000000
Jalankan waktu 2: 6000
s: 400000000

Sekarang saya bertanya-tanya apakah tolok ukur saya benar-benar berarti tetapi saya mendapatkan hasil yang konsisten (variasi dalam ms) selama beberapa kali tolok ukur itu sendiri ... :) Sepertinya tidak ada gunanya mencoba dan mengoptimalkan ini ...


sunting: mengikuti komentar ptomli, saya mengganti 'angka' dengan 'i' dalam kode di atas dan mendapatkan hasil sebagai berikut selama 5 kali pelaksanaan:

Jalankan waktu 1: 11500
s: 788888890
Jalankan waktu 2: 8547
s: 788888890

Jalankan waktu 1: 11485
s: 788888890
Jalankan waktu 2: 8547
s: 788888890

Jalankan waktu 1: 11469
s: 788888890
Jalankan waktu 2: 8547
s: 788888890

Jalankan waktu 1: 11500
s: 788888890
Jalankan waktu 2: 8547
s: 788888890

Jalankan waktu 1: 11484
s: 788888890
Jalankan waktu 2: 8547
s: 788888890
Jean
sumber
1
Hanya untuk bersenang-senang, apa perbedaan antar distribusi nilai angka, dari katakanlah 0 menjadi satu triliun? :)
ptomli
0

Bagaimana dengan metode rekursif ini?

    private static int length = 0;

    public static int length(int n) {
    length++;
    if((n / 10) < 10) {
        length++;
    } else {
        length(n / 10);
    }
    return length;
}
Jedi Dula
sumber
0

solusi sederhana:

public class long_length {
    long x,l=1,n;
    for (n=10;n<x;n*=10){
        if (x/n!=0){
            l++;
        }
    }
    System.out.print(l);
}
mikegh
sumber
0

Solusi yang sangat sederhana:

public int numLength(int n) {
  for (int length = 1; n % Math.pow(10, length) != n; length++) {}
  return length;
}
VoidCatz
sumber
Saya tidak akan memanggil satu baris untuk loop dengan tubuh kosong yang sederhana. Atau modulo kekuatan 10 untuk melihat apakah Anda mendapatkan hal yang sama kembali (tidak bisakah Anda hanya menggunakan perbandingan?).
Teepeemm
0

Atau sebaliknya panjang Anda dapat memeriksa apakah jumlahnya lebih besar atau lebih kecil dari angka yang diinginkan.

    public void createCard(int cardNumber, int cardStatus, int customerId) throws SQLException {
    if(cardDao.checkIfCardExists(cardNumber) == false) {
        if(cardDao.createCard(cardNumber, cardStatus, customerId) == true) {
            System.out.println("Card created successfully");
        } else {

        }
    } else {
        System.out.println("Card already exists, try with another Card Number");
        do {
            System.out.println("Enter your new Card Number: ");
            scan = new Scanner(System.in);
            int inputCardNumber = scan.nextInt();
            cardNumber = inputCardNumber;
        } while(cardNumber < 95000000);
        cardDao.createCard(cardNumber, cardStatus, customerId);
    }
}

}

Szabi Zsoldos
sumber
Saya tidak mengerti. Sepertinya Anda menjawab pertanyaan yang berbeda.
Teepeemm
0

Saya belum melihat solusi berbasis perkalian. Logaritma, pembagian, dan solusi berbasis string akan menjadi agak sulit melawan jutaan kasus uji, jadi inilah satu untuk ints:

/**
 * Returns the number of digits needed to represents an {@code int} value in 
 * the given radix, disregarding any sign.
 */
public static int len(int n, int radix) {
    radixCheck(radix); 
    // if you want to establish some limitation other than radix > 2
    n = Math.abs(n);

    int len = 1;
    long min = radix - 1;

    while (n > min) {
        n -= min;
        min *= radix;
        len++;
    }

    return len;
}

Dalam basis 10, ini bekerja karena n pada dasarnya dibandingkan dengan 9, 99, 999 ... karena min adalah 9, 90, 900 ... dan n sedang dikurangi dengan 9, 90, 900 ...

Sayangnya, ini tidak portabel longhanya dengan mengganti setiap instance intkarena overflow. Di sisi lain, kebetulan ia akan bekerja untuk basis 2 dan 10 (tetapi gagal untuk sebagian besar basis lainnya). Anda akan membutuhkan tabel pencarian untuk titik-titik luapan (atau tes pembagian ... ew)

/**
 * For radices 2 &le r &le Character.MAX_VALUE (36)
 */
private static long[] overflowpt = {-1, -1, 4611686018427387904L,
    8105110306037952534L, 3458764513820540928L, 5960464477539062500L,
    3948651115268014080L, 3351275184499704042L, 8070450532247928832L,
    1200757082375992968L, 9000000000000000000L, 5054470284992937710L,
    2033726847845400576L, 7984999310198158092L, 2022385242251558912L,
    6130514465332031250L, 1080863910568919040L, 2694045224950414864L,
    6371827248895377408L, 756953702320627062L, 1556480000000000000L,
    3089447554782389220L, 5939011215544737792L, 482121737504447062L,
    839967991029301248L, 1430511474609375000L, 2385723916542054400L,
    3902460517721977146L, 6269893157408735232L, 341614273439763212L,
    513726300000000000L, 762254306892144930L, 1116892707587883008L,
    1617347408439258144L, 2316231840055068672L, 3282671350683593750L,
    4606759634479349760L};

public static int len(long n, int radix) {
    radixCheck(radix);
    n = abs(n);

    int len = 1;
    long min = radix - 1;
    while (n > min) {
        len++;
        if (min == overflowpt[radix]) break;
        n -= min;
        min *= radix;

    }

    return len;
}
Jonathan Smith
sumber
0

Dengan desain (berdasarkan masalah). Ini adalah alternatif dari divide-and-conquer. Kami pertama-tama akan mendefinisikan enum (mengingat itu hanya untuk int yang tidak ditandatangani).

public enum IntegerLength {
    One((byte)1,10),
    Two((byte)2,100),
    Three((byte)3,1000),
    Four((byte)4,10000),
    Five((byte)5,100000),
    Six((byte)6,1000000),
    Seven((byte)7,10000000),
    Eight((byte)8,100000000),
    Nine((byte)9,1000000000);

    byte length;
    int value;

    IntegerLength(byte len,int value) {
        this.length = len;
        this.value = value;
    }

    public byte getLenght() {
        return length;
    }

    public int getValue() {
        return value;
    }
}

Sekarang kita akan mendefinisikan kelas yang melewati nilai enum dan membandingkan dan mengembalikan panjang yang sesuai.

public class IntegerLenght {
    public static byte calculateIntLenght(int num) {    
        for(IntegerLength v : IntegerLength.values()) {
            if(num < v.getValue()){
                return v.getLenght();
            }
        }
        return 0;
    }
}

Run time dari solusi ini sama dengan pendekatan divide-and-conquer.

Androider
sumber
Divide-and-conquer akan dimulai di tengah dan membagi dua area pencarian yang tersisa. Ini memiliki waktu menjalankan linier. Tapi itu tidak masalah hanya untuk 9 perbandingan. Tapi bukankah ini akan berantakan jika num>=Nine.getValue()?
Teepeemm
0

Seseorang ingin melakukan ini sebagian besar karena dia ingin "menyajikan", yang sebagian besar berarti akhirnya harus "toString-ed" (atau diubah dengan cara lain) secara eksplisit atau implisit pula; sebelum dapat disajikan (dicetak misalnya).

Jika itu masalahnya, maka cobalah membuat "toString" yang diperlukan secara eksplisit dan hitung bitnya.

howToDeleteMyAccount
sumber
0

Kita dapat mencapai ini menggunakan loop rekursif

    public static int digitCount(int numberInput, int i) {
        while (numberInput > 0) {
        i++;
        numberInput = numberInput / 10;
        digitCount(numberInput, i);
        }
        return i;
    }

    public static void printString() {
        int numberInput = 1234567;
        int digitCount = digitCount(numberInput, 0);

        System.out.println("Count of digit in ["+numberInput+"] is ["+digitCount+"]");
    }
ericdemo07
sumber
0

Saya menulis fungsi ini setelah mencari Integer.javakode sumber.

private static int stringSize(int x) {
    final int[] sizeTable = {9, 99, 999, 9_999, 99_999, 999_999, 9_999_999,
            99_999_999, 999_999_999, Integer.MAX_VALUE};
    for (int i = 0; ; ++i) {
        if (x <= sizeTable[i]) {
            return i + 1;
        }
    }
}
shellhub
sumber
0

Saya melihat orang-orang menggunakan perpustakaan String atau bahkan menggunakan kelas Integer. Tidak ada yang salah dengan itu tetapi algoritma untuk mendapatkan jumlah digit tidak terlalu rumit. Saya menggunakan panjang dalam contoh ini tetapi berfungsi dengan baik dengan int.

 private static int getLength(long num) {

    int count = 1;

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

    return count;
}
Sameer Khanal
sumber
0

tanpa API String, tanpa utils, tanpa konversi tipe, hanya iterasi java murni ->

public static int getNumberOfDigits(int input) {
    int numOfDigits = 1;
    int base = 1;
    while (input >= base * 10) {
        base = base * 10;
        numOfDigits++;
    }
    return numOfDigits;
 }

Anda bisa merindukan nilai yang lebih besar jika Anda mau.

Sahil
sumber
-1
    int num = 02300;
    int count = 0;
    while(num>0){
         if(num == 0) break;
         num=num/10;
         count++;
    }
    System.out.println(count);
kanakangi
sumber
Solusi "bagi dengan 10" pertama kali diposting oleh Sinista dua tahun sebelumnya.
Teepeemm
-1

Cara rekursif mudah

int    get_int_lenght(current_lenght, value)
{
 if (value / 10 < 10)
    return (current_lenght + 1);
return (get_int_lenght(current_lenght + 1, value))
}

tidak diuji

Valérian Polizzi
sumber
3
Anda mungkin harus mengujinya (dan pastikan itu Java yang valid dan diformat dengan benar). Tapi pendekatan "divide by 10" rekursif diposting oleh Jedi Dula 3 tahun yang lalu.
Teepeemm
-2

Anda dapat menggunakan digit dengan pembagian berurutan sebanyak sepuluh:

int a=0;

if (no < 0) {
    no = -no;
} else if (no == 0) {
    no = 1;
}

while (no > 0) {
    no = no / 10;
    a++;
}

System.out.println("Number of digits in given number is: "+a);
pengguna1590262
sumber
Pendekatan "divide by 10" pertama kali diposting oleh Sinista 3 tahun yang lalu. Itulah satu-satunya alasan saya dapat berpikir bahwa Anda mendapat downvote.
Teepeemm
-2

Masukkan nomor dan buat Arraylist, dan loop sementara akan mencatat semua digit ke dalam Arraylist. Lalu kita bisa mengambil ukuran array, yang akan menjadi panjang nilai integer yang Anda masukkan.

ArrayList<Integer> a=new ArrayList<>();

while(number > 0) 
{ 
    remainder = num % 10; 
    a.add(remainder);
    number = number / 10; 
} 

int m=a.size();
dev
sumber
1
Kecuali bahwa Anda tidak memerlukan ArrayList atau digit.
Marquis of Lorne
-2

Inilah metode yang sangat sederhana yang saya buat yang berfungsi untuk nomor apa pun:

public static int numberLength(int userNumber) {

    int numberCounter = 10;
    boolean condition = true;
    int digitLength = 1;

    while (condition) {
        int numberRatio = userNumber / numberCounter;
        if (numberRatio < 1) {
            condition = false;
        } else {
            digitLength++;
            numberCounter *= 10;
        }
    }

    return digitLength; 
}

Cara kerjanya adalah dengan variabel penghitung angka yaitu 10 = 1 digit spasi. Misalnya .1 = 1 persepuluh => 1 digit spasi. Karenanya, jika Anda memilikinya, int number = 103342;Anda akan mendapatkan 6, karena itu setara dengan 0,000001 spasi kembali. Juga, apakah ada yang punya nama variabel yang lebih baik numberCounter? Saya tidak bisa memikirkan yang lebih baik.

Sunting: Pikirkan penjelasan yang lebih baik. Pada dasarnya apa yang dilakukan loop ini adalah membuatnya Anda membagi angka dengan 10, sampai kurang dari satu. Pada dasarnya, ketika Anda membagi sesuatu dengan 10 Anda memindahkannya kembali satu ruang angka, jadi Anda cukup membaginya dengan 10 sampai Anda mencapai <1 untuk jumlah digit dalam nomor Anda.

Berikut ini versi lain yang dapat menghitung jumlah angka dalam desimal:

public static int repeatingLength(double decimalNumber) {

    int numberCounter = 1;
    boolean condition = true;
    int digitLength = 1;

    while (condition) {
        double numberRatio = decimalNumber * numberCounter;

        if ((numberRatio - Math.round(numberRatio)) < 0.0000001) {
            condition = false;
        } else {
            digitLength++;
            numberCounter *= 10;
        }
    }
    return digitLength - 1;
}
Andrew Patterson
sumber
-3

Cobalah mengubah int ke string yang dan kemudian mendapatkan panjang tali . Itu harus mendapatkan panjang int .

public static int intLength(int num){
    String n = Integer.toString(num);
    int newNum = n.length();
    return newNum;
}
pengguna5458400
sumber
Ini sama dengan kode asli. Dan akan ketinggalan bila numbernegatif.
Teepeemm