Maneira de obter o número de dígitos em um int?

386

Existe uma maneira mais clara de obter o comprimento de um int que esse método?

int length = String.valueOf(1000).length();
primeiro
fonte
7
defina o comprimento de um int por favor.
Tom
24
Eu acho que ele quer contar os dígitos no número.
Alberto Zaccagni
3
As respostas que as pessoas estão dando a você estão corretas ... elas fornecem o comprimento de você int sem convertê-lo em uma string ... mas por que você não deseja convertê-lo em uma string? É uma coisa de velocidade? Se assim for, não estou convencido de que esses métodos será mais rápido ... você pode querer fazer alguns testes (ou decidir se ele ainda importa.)
Beska
3
Os dígitos hexadecimais do @ptomli ainda são dígitos, apenas em um sistema base diferente.
Mark Pim
2
@Ptomli Claro, mas tanto na função Integer.toString quanto na conversa geral, decimal é o padrão. Quando o banco me diz: "Escreva o valor do seu cheque nesta caixa", não pergunto se devo escrevê-lo em decimal, hexadecimal ou octal. Assumimos decimal, a menos que especificado de outra forma ou chamado por contexto.
Jay

Respostas:

349

Sua solução baseada em String está perfeitamente bem, não há nada "arrumado" nela. Você deve perceber que matematicamente, os números não têm comprimento nem têm dígitos. Comprimento e dígitos são propriedades de uma representação física de um número em uma base específica, isto é, uma String.

Uma solução baseada em logaritmo faz (algumas) as mesmas coisas que uma baseada em String faz internamente, e provavelmente o faz (insignificantemente) mais rapidamente porque produz apenas o comprimento e ignora os dígitos. Mas eu realmente não consideraria isso mais claro em termos de intenção - e esse é o fator mais importante.

Michael Borgwardt
fonte
54
+1 para considerar intenção do código ao escolher uma maneira de resolver um problema
pupeno
5
Datapoint: Na minha máquina, o método log parece ser executado apenas duas vezes mais rápido que os métodos de comprimento de string. Eu não chamaria isso de insignificante se o método for chamado muito ou em uma seção de código de tempo crítico.
cperkins
11
Veja meu teste unitário de benchmark abaixo (que também pode ter falhas, eu não sou especialista em benchmark). Em um grande número de execuções (100.000.000), a velocidade é de 11s a 8s na minha máquina quase o dobro da velocidade.
Jean
5
@CPerkins. Otimização prematura. Você conhece o discurso.
22610 Michael Borgwardt
11
Alguns (bastante tarde) adição: pode não funcionar corretamente para valores negativos, dependendo se você espera que o "-" seja um dígito ou não. A adição Math.abs()corrigirá isso, no entanto.
YingYang
265

O logaritmo é seu amigo:

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

NB: válido apenas para n> 0.

Dmitry Brant
fonte
2
E isso é mais rápido ou melhor do que usar minha variante?
fnst 20/08/09
+1 Você me venceu por um segundo e sua resposta estava certa, onde a minha estava um pouco fora. Note, porém, que o compilador vai reclamar devido a um elenco que faltava para int
Dirk
2
@ Tom Por que você acha que é caro? Pode-se supor que o co-processador matemático o executaria, portanto, pode estar próximo da velocidade de uma adição. Mesmo que o java não use o co-processador agora, é uma boa suposição de que ele possa ... (Vamos ignorar sua implicação ainda mais instruída de que o Java é lento porque você provavelmente não está interessado em evidências - ou se você fosse você iria para shootout.alioth.debian.org e descobrir por si mesmo)
Bill K
8
Funciona ... a menos que o valor que você está verificando = 0, o que fornecerá resultados ímpares (-2147483647). API Math.log10: "Se o argumento for zero positivo ou zero negativo, o resultado será infinito negativo".
22312 mujimu
2
+1 Apresentando um método que não envolve alocações de memória de objeto, que é essencial para maximizar a reutilização para evitar coleções de GC.
Michael Wojcik
159

A abordagem mais rápida: dividir e conquistar.

Supondo que seu intervalo seja de 0 a MAX_INT, você tem de 1 a 10 dígitos. Você pode abordar esse intervalo usando dividir e conquistar, com até 4 comparações por cada entrada. Primeiro, você divide [1..10] em [1..5] e [6..10] com uma comparação e, em seguida, a cada intervalo 5, você divide usando uma comparação em um intervalo 3 e um comprimento 2. O intervalo de comprimento 2 requer mais uma comparação (total de 3 comparações), o intervalo de comprimento 3 pode ser dividido em intervalo de comprimento 1 (solução) e um intervalo de duração 2. Então, você precisa de 3 ou 4 comparações.

Sem divisões, operações de ponto flutuante, logaritmos dispendiosos, apenas comparações de números inteiros.

Código (longo mas rápido):

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

Referência (após o aquecimento da JVM) - veja o código abaixo para ver como a referência foi executada:

  1. método de linha de base (com String.length): 2145ms
  2. método log10: 711ms = 3,02 vezes mais rápido que a linha de base
  3. divisão repetida: 2797ms = 0,77 vezes mais rápido que a linha de base
  4. dividir e conquistar: 74ms = 28,99
    vezes mais rápido que a linha de base

Código 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;
}

Mais uma vez, benchmark:

  1. método de linha de base (com String.length): 2145ms
  2. método log10: 711ms = 3,02 vezes mais rápido que a linha de base
  3. divisão repetida: 2797ms = 0,77 vezes mais rápido que a linha de base
  4. dividir e conquistar: 74ms = 28,99
    vezes mais rápido que a linha de base

Edit: Depois que escrevi o benchmark, dei uma espiada no Integer.toString do Java 6 e descobri que ele usa:

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

Comparei-o com a minha solução de dividir e conquistar:

  1. dividir e conquistar: 104ms
  2. Solução Java 6 - itere e compare: 406ms

O meu é cerca de 4x mais rápido que a solução Java 6.

Marian
fonte
7
isso parece ótimo. você poderia escrevê-lo um pouco mais compacta usando o operador?: para obter mais aceitação
André Pareis
88
falar sobre otimização prematura: D
Gordon Gustafson
2
Eu gosto disso! Que tal um bloco de switch em vez de if-elseses tão aninhados?
Kebman #
2
Eu não percebi todas essas instruções if else seriam MUITO mais rápidas do que converter o int em String e depois chamar .length. +1
Ogen
15
Usando o operador ternário, traz para baixo a 101 caracteres: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

Dois comentários sobre seu benchmark: Java é um ambiente complexo, com compilação e coleta de lixo just-in-time e assim por diante, para obter uma comparação justa, sempre que executo um benchmark, sempre: (a) coloque os dois testes em um loop que os executa na sequência 5 ou 10 vezes. Muitas vezes, o tempo de execução na segunda passagem pelo loop é bem diferente da primeira. E (b) Após cada "abordagem", faço um System.gc () para tentar acionar uma coleta de lixo. Caso contrário, a primeira abordagem pode gerar um monte de objetos, mas não o suficiente para forçar uma coleta de lixo; a segunda abordagem cria alguns objetos, o heap está esgotado e a coleta de lixo é executada. Em seguida, a segunda abordagem é "cobrada" pela coleta do lixo deixado pela primeira abordagem. Muito injusto!

Dito isto, nenhum dos itens acima fez uma diferença significativa neste exemplo.

Com ou sem essas modificações, obtive resultados muito diferentes dos resultados obtidos. Quando eu executei isso, sim, a abordagem toString forneceu tempos de execução de 6400 a 6600 millis, enquanto a abordagem de log ultrapassou 20.000 a 20.400 millis. Em vez de ser um pouco mais rápida, a abordagem do log foi três vezes mais lenta para mim.

Observe que as duas abordagens envolvem custos muito diferentes, portanto, isso não é totalmente chocante: a abordagem toString criará muitos objetos temporários que precisam ser limpos, enquanto a abordagem de log exige uma computação mais intensa. Portanto, talvez a diferença seja que em uma máquina com menos memória, o toString requer mais rodadas de coleta de lixo, enquanto em uma máquina com um processador mais lento, o cálculo extra do log seria mais doloroso.

Eu também tentei uma terceira abordagem. Eu escrevi esta pequena função:

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

Isso foi executado entre 1600 e 1900 milissegundos - menos de 1/3 da abordagem toString e 1/10 da abordagem de log na minha máquina.

Se você tivesse uma ampla variedade de números, poderia acelerar ainda mais, dividindo por 1.000 ou 1.000.000 para reduzir o número de vezes no loop. Eu não brinquei com isso.

Jay
fonte
Você já tentou variar a entrada? Caso contrário, a VM do hotspot poderia otimizar esse gráfico, resultando em benchmarks errados, pois sempre retornava a mesma coisa pré-computada.
Erik Aigner
11

Usando Java

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

use import java.lang.Math.*;no começo

Usando C

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

use inclue math.hno começo

Santosh
fonte
11
Apenas para sua informação, resultará em infinito, se the_integerfor 0, então verifique isso.
Erik Aigner
10

Não é possível deixar um comentário ainda, então postarei como uma resposta separada.

A solução baseada em logaritmo não calcula o número correto de dígitos para números inteiros muito grandes, por exemplo:

long n = 99999999999999999L;

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

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

Solução baseada em logaritmo calcula número incorreto de dígitos em números inteiros grandes

alegre
fonte
tente (int) (Math.log10 (n + j)) em vez de onde j é 10 - (n - n / 10 * 10).
Erick Stone
8

Como o número de dígitos na base 10 de um número inteiro é apenas 1 + truncado (log10 (número)) , você pode:

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

Editado porque minha última edição corrigiu o exemplo de código, mas não a descrição.

Dirk
fonte
Legal. mas acho que precisa de abs (número) e também "0" é um caso especial também?
DmitryK
Sim. Se você precisar dar conta do sinal, precisará fazer algo como 1 + (int) Math.floor (Math.log10 (Math.abs (número))) + ((número <0)? 1: 0)
Dirk
5
O Math.flooré um pouco redundante, não é? A transmissão para intarredondará para baixo de qualquer maneira.
CompuChip
5

A solução da Marian adaptada para números longos (até 9.223.372.036.854.775.807), caso alguém queira copiá-lo e colá-lo. No programa que escrevi para números até 10000 eram muito mais prováveis, então criei um ramo específico para eles. De qualquer forma, não fará uma diferença 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;
                }
            }
        }
    }
}
CADEIA
fonte
O título dessa pergunta deve ser alterado para "Maneira de obter o número de dígitos em um int / long?" (e adicionou a tag 'long')
JAIL
4

Outra abordagem de string. Curto e doce - para qualquer número inteiro n.

int length = ("" + n).length();
ThisClark
fonte
Funciona apenas para números inteiros positivos ne zero. Pode ser usado ("" + Math.abs(n)).length()para obter comprimento inteiro negativo.
ThisClark
3

Posso tentar? ;)

com base na solução de Dirk

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

Que tal matemática antiga? Divida por 10 até chegar a 0.

public static int getSize(long number) {
        int count = 0;
        while (number > 0) {
            count += 1;
            number = (number / 10);
        }
        return count;
    }
Sinista
fonte
11
Você já testou? Você sabe que, por mais difícil que faça sentido para um ponto de vista humano, na verdade não funciona da mesma maneira com o "modo de pensar" da máquina, certo? --- Deixe-me propor uma coisa: faça uma matriz de dois milhões de números, de preferência Long.MAX_VALUE, qual é o pior caso de complexidade do seu código e use-o System.nanoTime()para fazer um teste de clock contra os piores casos de complexidade da outra solução. ++ Na verdade, tente com uma matriz preenchida por um randomizador definido como também 0para Long.MAX_VALUE, apenas para o teste de "complexidade média" ++ Você pode encontrar os resultados ... muito chocantes.
XenoRo 11/10/12
@ thelima Isso não funciona corretamente para zero ou negativos, mas é um bug menor. O princípio parece correto para mim. A que resultado "chocante" você está se referindo?
Jay
Digamos apenas que os computadores ... Bem ... Eles não gostam de se dividir. E nos casos em que grandes "filas" de grandes números precisam ser processadas, e cada dígito em cada número processado exigirá uma divisão ... Bem ... As coisas "começam a ficar muito lentas muito rápido" ... Se você pegar o meu significado ... --- É por isso que você vê muitas das respostas aqui usando códigos baseados em teste e comparação com cada dígito decimal usando 'if's, em vez de divisões: se não for mais rápido, pelo menos mantém a maior parte da velocidade, independentemente dos piores casos. --- Faça um teste entre o uso de divisões e logaritmo em grandes números ...
XenoRo 6/14
@TheLima do que você está falando? Para int,esse loop, ele executa no máximo 11 vezes. Você tem alguma evidência para suas afirmações?
Marquês de Lorne
@EJP Do ponto de vista do hardware, a divisão é um processo iterativo. O algoritmo de divisão mais rápido que conheço é o radix4, que gera 4 bits por iteração; portanto, uma divisão de 32 bits precisa de pelo menos 8 iterações. Multiplicações, por exemplo, podem ser feitas em paralelo e também divididas em multiplicações mais simples; no nível de bit (exigindo apenas 5 operações) ou com quebra parcial mais uma tabela de consulta no final (troca de velocidade VS de tamanho clássico). Não se trata apenas de "quantas iterações"; o problema com divisões mentiras com "o que cada iteração implica / faz, a um nível de hardware"
XenoRo
2

Solução da Marian, agora com 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)));
    }

Porque nós podemos.

Usuário não encontrado
fonte
2
Isso é meio difícil de ler. Talvez adicione alguns espaços e / ou novas linhas.
michaelb958 - GoFundMonica
Mas caramba, é portátil!
Trevor Rudolph
1

Curioso, tentei compará-lo ...

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


    }
}

os resultados são:

Tempo de execução 1: 6765
s: 400000000
Tempo de execução 2: 6000
s: 400000000

Agora, fico me perguntando se meu benchmark realmente significa alguma coisa, mas eu obtenho resultados consistentes (variações dentro de um ms) em várias execuções do próprio benchmark ... :) Parece que é inútil tentar otimizar isso ...


edit: após o comentário de ptomli, substitui 'number' por 'i' no código acima e obtive os seguintes resultados em 5 execuções do banco:

Tempo de execução 1: 11500
s: 788888890
Tempo de execução 2: 8547
s: 788888890

Tempo de execução 1: 11485
s: 788888890
Tempo de execução 2: 8547
s: 788888890

Tempo de execução 1: 11469
s: 788888890
Tempo de execução 2: 8547
s: 788888890

Tempo de execução 1: 11500
s: 788888890
Tempo de execução 2: 8547
s: 788888890

Tempo de execução 1: 11484
s: 788888890
Tempo de execução 2: 8547
s: 788888890
Jean
fonte
11
Apenas por diversão, qual é a diferença entre uma distribuição de valores numéricos, de 0 a 1 trilhão? :)
ptomli 20/08/09
0

E esse método recursivo?

    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
fonte
0

solução simples:

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
fonte
0

Uma solução realmente simples:

public int numLength(int n) {
  for (int length = 1; n % Math.pow(10, length) != n; length++) {}
  return length;
}
VoidCatz
fonte
Eu não chamaria uma linha de loop simples com um corpo vazio. Nem module uma potência de 10 para ver se você recebe a mesma coisa de volta (você não pode simplesmente usar uma comparação?).
Teepeemm
0

Ou então o comprimento que você pode verificar se o número é maior ou menor que o número desejado.

    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
fonte
Eu não entendo Parece que você está respondendo a uma pergunta diferente.
Teepeemm
0

Ainda não vi uma solução baseada em multiplicação. As soluções baseadas em logaritmo, divisão e cadeia de caracteres tornar-se-ão difíceis de manejar contra milhões de casos de teste, então aqui está um para 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;
}

Na base 10, isso funciona porque n é essencialmente comparado a 9, 99, 999 ... como min é 9, 90, 900 ... en é subtraído por 9, 90, 900 ...

Infelizmente, isso não é portátil longapenas substituindo todas as instâncias do intdevido ao estouro. Por outro lado, acontece que ele irá trabalhar para bases 2 e 10 (mas mal não para a maioria das outras bases). Você precisará de uma tabela de pesquisa para os pontos de estouro (ou um teste de divisão ... 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
fonte
0

Com design (baseado no problema). Esta é uma alternativa de dividir e conquistar. Primeiro, definiremos uma enumeração (considerando que é apenas para um int não assinado).

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

Agora vamos definir uma classe que passa pelos valores da enumeração, comparar e retornar o comprimento apropriado.

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

O tempo de execução dessa solução é o mesmo da abordagem de dividir e conquistar.

bordar
fonte
Uma divisão e conquista começaria no meio e dividiria a área de pesquisa restante. Isso tem um tempo de execução linear. Mas isso não importa para apenas 9 comparações. Mas isso não vai atrapalhar se num>=Nine.getValue()?
Teepeemm
0

Quer-se fazer isso principalmente porque ele / ela quer "apresentá-lo", o que geralmente significa que ele finalmente precisa ser "editado por strings" (ou transformado de outra maneira) explícita ou implicitamente; antes de poder ser apresentado (impresso por exemplo).

Se for esse o caso, tente explicitar o "toString" necessário e conte os bits.

Como deleto minha conta
fonte
0

Podemos conseguir isso usando um loop recursivo

    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
fonte
0

Eu escrevi essa função depois de procurar o Integer.javacódigo fonte.

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
fonte
0

Eu vejo pessoas usando bibliotecas de String ou mesmo usando a classe Integer. Nada de errado com isso, mas o algoritmo para obter o número de dígitos não é tão complicado. Estou usando um longo neste exemplo, mas funciona tão bem com um int.

 private static int getLength(long num) {

    int count = 1;

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

    return count;
}
Sameer Khanal
fonte
0

API sem String, sem utilitários, sem conversão de tipo, apenas iteração java pura ->

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

Você pode comprar valores maiores, se quiser.

Sahil
fonte
-1
    int num = 02300;
    int count = 0;
    while(num>0){
         if(num == 0) break;
         num=num/10;
         count++;
    }
    System.out.println(count);
kanakangi
fonte
Uma solução "dividir por 10" foi lançada pela Sinista dois anos antes.
22415 Teepeemm
-1

Maneira fácil recursiva

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

não testado

Valérian Polizzi
fonte
3
Provavelmente você deve testá-lo (e verifique se ele é Java válido e formatado corretamente). Mas uma abordagem recursiva de "dividir por 10" foi publicada por Jedi Dula há 3 anos.
Teepeemm
-2

Você poderia os dígitos usando a divisão sucessiva por dez:

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);
user1590262
fonte
Uma abordagem de "dividir por 10" foi publicada pela Sinista há 3 anos. Essa é a única razão pela qual consigo pensar que você recebeu um voto negativo.
Teepeemm
-2

Digite o número e crie um Arraylist, e o loop while registrará todos os dígitos no Arraylist. Então podemos tirar o tamanho da matriz, que será o comprimento do valor inteiro que você digitou.

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

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

int m=a.size();
dev
fonte
11
Exceto que você não precisa do ArrayList ou dos dígitos.
Marquês de Lorne
-2

Aqui está um método realmente simples que eu criei que funciona para qualquer número:

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

O modo como funciona é com a variável do contador numérico é o espaço de 10 = 1 dígito. Por exemplo .1 = 1 décimo => espaço de 1 dígito. Portanto, se você tiver, int number = 103342;receberá 6, porque isso equivale a 0,00001 espaços de volta. Além disso, alguém tem um nome de variável melhor paranumberCounter ? Não consigo pensar em nada melhor.

Edit: Apenas pensei em uma explicação melhor. Essencialmente, o que esse loop while está fazendo é fazer com que você divida seu número por 10, até que seja menor que um. Essencialmente, quando você divide algo por 10, você está movendo-o para trás um espaço numérico, então você simplesmente o divide por 10 até chegar a <1 para a quantidade de dígitos no seu número.

Aqui está outra versão que pode contar a quantidade de números em um decimal:

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
fonte
-3

Tente converter o int em uma sequência e obtenha o comprimento da sequência . Isso deve ter a duração do int .

public static int intLength(int num){
    String n = Integer.toString(num);
    int newNum = n.length();
    return newNum;
}
user5458400
fonte
Isso é completamente equivalente ao código original. E vai sentir falta quando numberé negativo.
Teepeemm