Modo per ottenere il numero di cifre in un int?


386

Esiste un modo più ordinato per ottenere la lunghezza di un int rispetto a questo metodo?

int length = String.valueOf(1000).length();

7
definire la lunghezza di un int per favore.
Tom,

24
Penso che voglia contare le cifre nel numero.
Alberto Zaccagni,

3
Le risposte che le persone ti stanno dando sono corrette ... ti danno la lunghezza di te int senza convertirlo in una stringa ... ma perché non vuoi convertirlo in una stringa? È una cosa veloce? Se è così, io non sono convinto che questi metodi saranno più veloce ... si potrebbe desiderare di fare alcuni test (o decidere se è importante anche.)
Beska

3
Le cifre esadecimali di @ptomli sono ancora cifre, solo in un diverso sistema di base.
Mark Pim,

2
@Ptomli Certo, ma sia nella funzione Integer.toString, sia nella conversazione generale, il valore decimale è l'impostazione predefinita. Quando la banca mi dice "Scrivi l'importo del tuo assegno in questa casella", non chiedo loro se devo scriverlo in decimale, esadecimale o ottale. Assumiamo il decimale se non diversamente specificato o richiesto dal contesto.
Jay,

Risposte:


349

La tua soluzione basata su String è perfettamente OK, non c'è nulla di "non ordinato" al riguardo. Devi capire che matematicamente, i numeri non hanno una lunghezza, né hanno cifre. La lunghezza e le cifre sono entrambe proprietà di una rappresentazione fisica di un numero in una base specifica, ovvero una stringa.

Una soluzione basata su logaritmo fa (alcune) le stesse cose che quella basata su String fa internamente, e probabilmente lo fa (in modo insignificante) più velocemente perché produce solo la lunghezza e ignora le cifre. Ma in realtà non lo considererei più chiaro nelle intenzioni - e questo è il fattore più importante.


54
+1 per considerare l'intento del codice quando si
sceglie

5
Datapoint: Sulla mia macchina, il metodo di registro sembra funzionare solo due volte più veloce dei metodi di lunghezza della stringa. Non lo definirei insignificante se il metodo viene chiamato molto o in una sezione di codice critica nel tempo.
CPerkins,

1
Vedi il mio test unitario di riferimento di seguito (che potrebbe anche essere imperfetto, non sono un esperto di benchmark). In un gran numero di corse (100.000.000), la mia velocità è compresa tra 11 e 8 secondi sulla mia macchina quasi due volte più veloce.
Jean,

5
@CPerkins. Ottimizzazione prematura. Conosci lo spiel.
Michael Borgwardt,

11
Qualche aggiunta (piuttosto tardi): potrebbe non funzionare correttamente per valori negativi, a seconda se si prevede che il "-" sia una cifra o meno. L'aggiunta Math.abs()risolverà questo, però.
YingYang

265

Il logaritmo è tuo amico:

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

NB: valido solo per n> 0.


2
Ed è più veloce o migliore dell'uso della mia variante?
primo

+1 Mi hai battuto per un secondo e la tua risposta era giusta, dove la mia era leggermente off. Si noti, tuttavia, che il compilatore si lamenterà a causa di un cast mancante a int
Dirk,

2
@ Tom Perché pensi che sia costoso? Si potrebbe supporre che il coprocessore matematico lo esegua, quindi potrebbe essere vicino alla velocità di un'aggiunta. Anche se java non utilizza il coprocessore ora, è una buona ipotesi che potrebbe ... (Ignoreremo semplicemente le tue implicazioni ancora meno istruttive sul fatto che Java sia lento perché probabilmente non sei interessato alle prove - o se tu fossi andresti su shootout.alioth.debian.org e lo scopriresti da solo)
Bill K

8
Funziona ... a meno che il valore che stai controllando = 0, che ti darà risultati dispari (-2147483647). API Math.log10: "Se l'argomento è zero positivo o zero negativo, il risultato è infinito negativo."
mujimu,

2
+1 Presentazione di un metodo che non comporta allocazioni di memoria degli oggetti, indispensabile per massimizzare il riutilizzo per evitare raccolte GC.
Michael Wojcik,

159

L'approccio più veloce: dividere e conquistare.

Supponendo che l'intervallo sia compreso tra 0 e MAX_INT, si hanno da 1 a 10 cifre. Puoi avvicinarti a questo intervallo usando divide and conquer, con un massimo di 4 confronti per ogni input. Innanzitutto, dividi [1..10] in [1..5] e [6..10] con un confronto, quindi ogni intervallo di lunghezza 5 che dividi usando un confronto in un intervallo di lunghezza 3 e lunghezza 2. L'intervallo lunghezza 2 richiede un ulteriore confronto (totale 3 confronti), l'intervallo lunghezza 3 può essere diviso in intervallo lunghezza 1 (soluzione) e un intervallo lunghezza 2. Quindi, hai bisogno di 3 o 4 confronti.

Nessuna divisione, nessuna operazione in virgola mobile, nessun logaritmo costoso, solo confronti interi.

Codice (lungo ma veloce):

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 (dopo il riscaldamento di JVM) - vedi il codice sotto per vedere come è stato eseguito il benchmark:

  1. metodo baseline (con String.length): 2145ms
  2. Metodo log10: 711ms = 3.02 volte più veloce della linea di base
  3. divisione ripetuta: 2797 ms = 0,77 volte più veloce della linea di base
  4. divide-and-conquer: 74ms = 28,99
    volte più veloce della linea di base

Codice completo:

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

Ancora una volta, benchmark:

  1. metodo baseline (con String.length): 2145ms
  2. Metodo log10: 711ms = 3.02 volte più veloce della linea di base
  3. divisione ripetuta: 2797 ms = 0,77 volte più veloce della linea di base
  4. divide-and-conquer: 74ms = 28,99
    volte più veloce della linea di base

Modifica: Dopo aver scritto il benchmark, ho preso un'anteprima di Integer.toString da Java 6 e ho scoperto che utilizza:

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

L'ho confrontato con la mia soluzione di divisione e conquista:

  1. Dividi e conquista: 104 ms
  2. Soluzione Java 6 - iterare e confrontare: 406ms

Il mio è circa 4x più veloce della soluzione Java 6.


7
sembra fantastico. potresti scriverlo un po 'più compatto usando l'operatore?: per ottenere una maggiore accettazione
André Pareis,

88
parlare di ottimizzazione prematura: D
Gordon Gustafson,

2
Mi piace! Che ne dici di un blocco switch invece di if-elses così nidificati?
Kebman,

2
Non mi rendevo conto di tutte queste affermazioni se altrimenti le istruzioni sarebbero state così veloci che convertire int in String e chiamare .length. +1
Ogen,

15
Usando l'operatore ternario, lo porta a 101 caratteri: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

Due commenti sul tuo benchmark: Java è un ambiente complesso, con compilazione just-in-time e garbage collection e così via, quindi per ottenere un confronto equo, ogni volta che eseguo un benchmark, io sempre: (a) allego i due test in un ciclo che li esegue in sequenza 5 o 10 volte. Abbastanza spesso il tempo di esecuzione al secondo passaggio attraverso il ciclo è abbastanza diverso dal primo. E (b) Dopo ogni "approccio", faccio un System.gc () per provare ad innescare una garbage collection. Altrimenti, il primo approccio potrebbe generare un mucchio di oggetti, ma non abbastanza per forzare una garbage collection, quindi il secondo approccio crea alcuni oggetti, l'heap è esaurito e viene eseguita la garbage collection. Quindi il secondo approccio viene "addebitato" per raccogliere la spazzatura lasciata dal primo approccio. Molto ingiusto!

Detto questo, nessuna delle precedenti ha fatto una differenza significativa in questo esempio.

Con o senza tali modifiche, ho ottenuto risultati molto diversi rispetto a te. Quando ho eseguito questo, sì, l'approccio toString ha dato tempi di esecuzione da 6400 a 6600 millis, mentre l'approccio log ha richiesto da 20.000 a 20.400 millis. Invece di essere leggermente più veloce, l'approccio log è stato 3 volte più lento per me.

Si noti che i due approcci comportano costi molto diversi, quindi questo non è del tutto scioccante: l'approccio toString creerà molti oggetti temporanei che devono essere ripuliti, mentre l'approccio log richiede un calcolo più intenso. Quindi forse la differenza è che su una macchina con meno memoria, toString richiede più round di garbage collection, mentre su una macchina con un processore più lento, il calcolo extra del log sarebbe più doloroso.

Ho anche provato un terzo approccio. Ho scritto questa piccola funzione:

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

Ciò è durato da 1600 a 1900 millis - meno di 1/3 dell'approccio toString e 1/10 dell'approccio log sulla mia macchina.

Se avessi una vasta gamma di numeri, potresti accelerare ulteriormente iniziando a dividere per 1.000 o 1.000.000 per ridurre il numero di volte attraverso il ciclo. Non ci ho giocato.


Hai provato a variare l'input? La macchina virtuale hotspot potrebbe altrimenti ottimizzare questo grafico, generando benchmark errati, perché restituisce sempre la stessa cosa pre-calcolata.
Erik Aigner,

11

Usando Java

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

usare import java.lang.Math.*;all'inizio

Usando C

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

usare inclue math.hall'inizio


1
Solo FYI, comporterà l'infinito se lo the_integerè 0, quindi controlla per quello.
Erik Aigner,

10

Non posso ancora lasciare un commento, quindi posterò una risposta separata.

La soluzione basata su logaritmo non calcola il numero corretto di cifre per numeri interi molto grandi, ad esempio:

long n = 99999999999999999L;

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

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

La soluzione basata su logaritmo calcola il numero errato di cifre in numeri interi grandi


provare (int) (Math.log10 (n + j)) invece dove j è 10 - (n - n / 10 * 10).
Erick Stone,

8

Poiché il numero di cifre nella base 10 di un numero intero è solo 1 + troncato (log10 (numero)) , puoi fare:

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

Modificato perché la mia ultima modifica ha corretto l'esempio di codice, ma non la descrizione.


Freddo. ma penso che abbia bisogno di abs (numero) e anche "0" è anche un caso speciale?
DmitryK,

Sì. Se devi tenere conto del segno, dovrai fare qualcosa come 1 + (int) Math.floor (Math.log10 (Math.abs (numero))) + ((numero <0)? 1: 0)
Dirk,

5
Il Math.floorè un po 'ridondante, non è vero? Lanciare per intarrotondarlo comunque.
CompuChip,

5

La soluzione di Marian è stata adattata per numeri di tipo lungo (fino a 9.223.372.036.854.775.807), nel caso in cui qualcuno voglia copiarlo e incollarlo. Nel programma ho scritto questo perché numeri fino a 10000 erano molto più probabili, quindi ho creato un ramo specifico per loro. Comunque non farà una differenza significativa.

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

Il titolo di questa domanda dovrebbe essere cambiato in "Modo di ottenere il numero di cifre in un int / long?" (e ha aggiunto il tag "lungo")
JAIL

4

Un altro approccio basato su stringhe. Breve e dolce - per qualsiasi numero intero n.

int length = ("" + n).length();

Funziona solo con numeri interi positivi ne zero. Può usare ("" + Math.abs(n)).length()per ottenere la lunghezza dell'intero negativo.
ThisClark,

3

Posso provare? ;)

basato sulla soluzione di Dirk

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

3

Che ne dici di vecchia matematica semplice? Dividi per 10 fino a raggiungere 0.

public static int getSize(long number) {
        int count = 0;
        while (number > 0) {
            count += 1;
            number = (number / 10);
        }
        return count;
    }

1
L'hai provato? Sai che, anche se ha senso per un punto di vista umano, non funziona davvero allo stesso modo con il "modo di pensare" della macchina, giusto? --- Lasciami proporre una cosa: crea una matrice di due milioni di numeri, preferibilmente Long.MAX_VALUE, che è il peggior caso di complessità del tuo codice, e usa System.nanoTime()per fare una prova di clock contro i peggiori casi di complessità dell'altra soluzione. ++ In realtà, provare con una matrice riempita da un insieme randomizer alla gamma di 0di Long.MAX_VALUEtroppo, solo per il "media complessità" testing ++ Si potrebbe trovare i risultati ... molto scioccante.
XenoRo,

@thelima Questo non funziona correttamente per zero o negativi, ma questo è un bug minore. Il principio mi sembra corretto. A quale risultato "scioccante" ti riferisci?
Jay,

Diciamo solo che i computer ... Beh ... A loro non piace dividere. E nei casi in cui devono essere elaborate grandi "code" di grandi numeri, e ogni cifra in ogni numero elaborato richiederà una divisione ... Beh ... Le cose "iniziano a rallentare davvero molto velocemente" ... Se prendi il mio significato ... --- Questo è il motivo per cui vedi molte delle risposte qui usando codici basati su test e confronto con ogni cifra decimale usando 'if's, piuttosto che divisioni: se non è più veloce, almeno mantiene la maggior parte della sua velocità indipendentemente dei suoi casi peggiori. --- Fai un test tra l'utilizzo di divisioni e logaritmo su grandi numeri ...
XenoRo

@TheLima di cosa stai parlando? Per int,questo questo ciclo esegue un massimo di 11 volte. Hai qualche prova per le tue affermazioni?
Marchese di Lorne,

@EJP Da un punto di vista hardware, la divisione è un processo iterativo. L'algoritmo di divisione più veloce che conosco è radix4, che genera 4 bit per iterazione; quindi una divisione a 32 bit richiede almeno 8 iterazioni. Le moltiplicazioni, per esempio, possono essere fatte in parallelo e possono anche essere suddivise in moltiplicazioni più semplici; o fino al livello di bit (che richiede solo 5 operazioni) o con suddivisione parziale più una tabella di ricerca alla fine (scambio di velocità VS di dimensioni classiche). Non si tratta solo di "quante iterazioni"; il problema con le divisioni è "ciò che ogni iterazione implica / fa, a livello hardware"
XenoRo,

2

Marian's Solution, ora con 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)));
    }

Perché possiamo.


2
È un po 'difficile da leggere. Forse aggiungere alcuni spazi e / o nuove righe.
michaelb958 - GoFundMonica

Ma accidenti è portatile!
Trevor Rudolph,

1

Curioso, ho provato a confrontarlo ...

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


    }
}

i risultati sono:

Tempo di esecuzione 1: 6765
s: 400000000
Tempo di esecuzione 2: 6000
s: 400000000

Ora mi chiedo se il mio benchmark in realtà significhi qualcosa ma ottengo risultati coerenti (variazioni in un ms) su più esecuzioni del benchmark stesso ... :) Sembra che sia inutile provare a ottimizzare questo ...


modifica: seguendo il commento di ptomli, ho sostituito 'numero' con 'i' nel codice sopra e ho ottenuto i seguenti risultati su 5 esecuzioni del banco:

Tempo di esecuzione 1: 11500
s: 788888890
Durata 2: 8547
s: 788888890

Tempo di esecuzione 1: 11485
s: 788888890
Durata 2: 8547
s: 788888890

Tempo di esecuzione 1: 11469
s: 788888890
Durata 2: 8547
s: 788888890

Tempo di esecuzione 1: 11500
s: 788888890
Durata 2: 8547
s: 788888890

Tempo di esecuzione 1: 11484
s: 788888890
Durata 2: 8547
s: 788888890

1
Solo per divertimento, qual è la differenza tra una distribuzione di valori di numero, da dire 0 a un trilione? :)
ptomli

0

Che dire di questo metodo ricorsivo?

    private static int length = 0;

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

0

soluzione semplice:

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

0

Una soluzione davvero semplice:

public int numLength(int n) {
  for (int length = 1; n % Math.pow(10, length) != n; length++) {}
  return length;
}

Non chiamerei una linea per loop con un corpo vuoto semplice. Né modulo una potenza di 10 per vedere se si ottiene indietro la stessa cosa (non si può semplicemente usare un confronto?).
Teepeemm,

0

O invece la lunghezza è possibile verificare se il numero è maggiore o minore del numero desiderato.

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

}


Non capisco. Sembra che tu stia rispondendo a una domanda diversa.
Teepeemm,

0

Non ho ancora visto una soluzione basata sulla moltiplicazione. Logaritmo, divison e soluzioni basate su stringhe diventeranno piuttosto ingombranti rispetto a milioni di casi di test, quindi eccone uno per 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;
}

Nella base 10, questo funziona perché n viene essenzialmente confrontato con 9, 99, 999 ... poiché min è 9, 90, 900 ... e n viene sottratto da 9, 90, 900 ...

Sfortunatamente, questo non è portatile longsemplicemente sostituendo ogni istanza di intcausa di overflow. D'altra parte, si dà il caso che si funzionerà per basi 2 e 10 (ma mal riesce per la maggior parte delle altre basi). Avrai bisogno di una tabella di ricerca per i punti di overflow (o un test di divisione ... 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;
}

0

Con design (basato sul problema). Questo è un alternato di dividi e conquista. Definiremo prima un enum (considerando che è solo per un int senza segno).

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

Ora definiremo una classe che passa attraverso i valori dell'enum e confronteremo e restituiremo la lunghezza appropriata.

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

Il tempo di esecuzione di questa soluzione è uguale all'approccio di divisione e conquista.


Una divisione e conquista inizierebbe nel mezzo e dividere in due l'area di ricerca rimanente. Questo ha un tempo di esecuzione lineare. Ma non importa solo per 9 confronti. Ma questo non rovinerà se num>=Nine.getValue()?
Teepeemm,

0

Uno vuole farlo principalmente perché vuole "presentarlo", il che significa che alla fine deve essere "forzato" (o trasformato in altro modo) in modo esplicito o implicito comunque; prima che possa essere presentato (stampato ad esempio).

In tal caso, prova a rendere esplicito il "toString" necessario e conta i bit.


0

Possiamo raggiungere questo obiettivo utilizzando un ciclo ricorsivo

    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+"]");
    }

0

Ho scritto questa funzione dopo aver cercato Integer.javail codice sorgente.

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

0

Vedo persone che usano le librerie String o addirittura usano la classe Integer. Niente di sbagliato in questo, ma l'algoritmo per ottenere il numero di cifre non è così complicato. Sto usando un lungo in questo esempio ma funziona altrettanto bene con un int.

 private static int getLength(long num) {

    int count = 1;

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

    return count;
}

0

nessuna API String, nessun programma di utilità, nessuna conversione di tipo, solo pura iterazione Java ->

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

Puoi andare avanti per valori più grandi, per favore.


-1
    int num = 02300;
    int count = 0;
    while(num>0){
         if(num == 0) break;
         num=num/10;
         count++;
    }
    System.out.println(count);

Una soluzione "divide per 10" è stata pubblicata per la prima volta da Sinista due anni prima.
Teepeemm,

-1

Modo semplice ricorsivo

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

non testato


3
Probabilmente dovresti testarlo quindi (e assicurarti che sia valido Java e formattato correttamente). Ma un approccio ricorsivo "divide per 10" è stato pubblicato da Jedi Dula 3 anni fa.
Teepeemm,

-2

È possibile inserire le cifre utilizzando la divisione successiva per dieci:

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

Un approccio "divide per 10" è stato pubblicato per la prima volta da Sinista 3 anni fa. Questa è l'unica ragione per cui riesco a pensare che hai ottenuto un voto negativo.
Teepeemm,

-2

Immettere il numero e creare un Arraylist, e il ciclo while registrerà tutte le cifre in Arraylist. Quindi possiamo rimuovere la dimensione dell'array, che sarà la lunghezza del valore intero inserito.

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

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

int m=a.size();

1
Solo che non hai bisogno di ArrayList o delle cifre.
Marchese di Lorne,

-2

Ecco un metodo davvero semplice che ho creato che funziona per qualsiasi numero:

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

Il modo in cui funziona è con la variabile contatore numerico è che lo spazio 10 = 1 cifra. Ad esempio .1 = 1 decimo => 1 cifra di spazio. Pertanto, se hai int number = 103342;, otterrai 6, perché questo è l'equivalente di .000001 spazi indietro. Inoltre, qualcuno ha un nome variabile migliore per numberCounter? Non riesco a pensare a niente di meglio.

Modifica: ho solo pensato a una spiegazione migliore. In sostanza ciò che sta facendo questo ciclo while è farlo in modo da dividere il numero per 10, fino a quando è inferiore a uno. In sostanza, quando dividi qualcosa per 10 lo stai spostando indietro di uno spazio numerico, quindi lo dividi semplicemente per 10 fino a raggiungere <1 per la quantità di cifre nel tuo numero.

Ecco un'altra versione che può contare la quantità di numeri in un decimale:

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

-3

Prova a convertire int in una stringa e ottieni la lunghezza della stringa . Questo dovrebbe ottenere la lunghezza del int .

public static int intLength(int num){
    String n = Integer.toString(num);
    int newNum = n.length();
    return newNum;
}

Questo è completamente equivalente al codice originale. E mancherà quando numberè negativo.
Teepeemm,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.