java - tipos - ¿Cómo obtener el número de dígitos en un int?
sumar digitos de un numero java (27)
¿Puedo intentar? ;)
basado en la solución de Dirk
final int digits = number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number))));
¿Hay una manera más ordenada para obtener la longitud de un int como esta?
int length = String.valueOf(1000).length();
¿Qué hay de Matemáticas antiguas? Divide entre 10 hasta llegar a 0.
public static int getSize(long number) {
int count = 0;
while (number > 0) {
count += 1;
number = (number / 10);
}
return count;
}
¿Qué pasa con este 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;
}
Aquí hay un método muy simple que hice que funciona para cualquier 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;
}
La forma en que funciona es con la variable del contador numérico es ese espacio de 10 = 1 dígito. Por ejemplo .1 = 1 décima => espacio de 1 dígito. Por lo tanto, si tiene int number = 103342;
obtendrá 6, porque eso es el equivalente de .000001 espacios atrás. Además, ¿alguien tiene un nombre de variable mejor para numberCounter
? No puedo pensar en nada mejor.
Edit: sólo pensé en una mejor explicación. Esencialmente, lo que está haciendo este bucle mientras lo hace es hacerlo, así que divide tu número entre 10, hasta que sea menor que uno. Esencialmente, cuando divides algo entre 10, lo mueves hacia atrás un espacio numérico, así que simplemente lo divides entre 10 hasta que alcances <1 para la cantidad de dígitos en tu número.
Aquí hay otra versión que puede contar la cantidad de números en un 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;
}
Como el número de dígitos en la base 10 de un entero es solo 1 + truncar (log10 (número)) , puede hacer:
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 mi última edición solucionó el ejemplo del código, pero no la descripción.
Con diseño (basado en problema). Esta es una alternativa de divide y vencerás. Primero definiremos una enumeración (considerando que es solo para un int sin signo).
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;
}
}
Ahora definiremos una clase que pasa por los valores de la enumeración y compararemos y devolveremos la longitud adecuada.
public class IntegerLenght {
public static byte calculateIntLenght(int num) {
for(IntegerLength v : IntegerLength.values()) {
if(num < v.getValue()){
return v.getLenght();
}
}
return 0;
}
}
El tiempo de ejecución de esta solución es el mismo que el enfoque de dividir y conquistar.
Curioso, traté de compararlo ...
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);
}
}
los resultados son:
Run time 1: 6765 s: 400000000 Run time 2: 6000 s: 400000000
Ahora me pregunto si mi índice de referencia realmente significa algo, pero sí obtengo resultados consistentes (variaciones dentro de un ms) en varias ejecuciones del propio índice de referencia ... :) Parece que es inútil tratar de optimizar esto ...
edición: siguiendo el comentario de ptomli, reemplacé ''número'' por ''i'' en el código anterior y obtuve los siguientes resultados en 5 ejecuciones del banco:
Run time 1: 11500 s: 788888890 Run time 2: 8547 s: 788888890 Run time 1: 11485 s: 788888890 Run time 2: 8547 s: 788888890 Run time 1: 11469 s: 788888890 Run time 2: 8547 s: 788888890 Run time 1: 11500 s: 788888890 Run time 2: 8547 s: 788888890 Run time 1: 11484 s: 788888890 Run time 2: 8547 s: 788888890
Dos comentarios sobre su punto de referencia: Java es un entorno complejo, con compilación y recolección de basura justo a tiempo, y así sucesivamente, para obtener una comparación justa, siempre que ejecute un punto de referencia, siempre: (a) incluyo las dos pruebas en un bucle que los ejecuta en secuencia 5 o 10 veces. Muy a menudo, el tiempo de ejecución en la segunda pasada a través del bucle es bastante diferente de la primera. Y (b) Después de cada "aproximación", hago un System.gc () para intentar activar una recolección de basura. De lo contrario, el primer enfoque podría generar un montón de objetos, pero no lo suficiente como para forzar una recolección de basura, luego el segundo enfoque crea algunos objetos, el montón se agota y se ejecuta la recolección de basura. Luego, el segundo enfoque se "cobra" por recoger la basura que dejó el primer enfoque. ¡Muy injusto!
Dicho esto, ninguno de los anteriores hizo una diferencia significativa en este ejemplo.
Con o sin esas modificaciones, obtuve resultados muy diferentes a los que tú recibiste. Cuando ejecuté esto, sí, el enfoque toString dio tiempos de ejecución de 6400 a 6600 millis, mientras que el enfoque de registro alcanzó 20,000 a 20,400 millis. En lugar de ser un poco más rápido, el enfoque de registro fue 3 veces más lento para mí.
Tenga en cuenta que los dos enfoques implican costos muy diferentes, por lo que esto no es totalmente chocante: el enfoque toString creará muchos objetos temporales que se deben limpiar, mientras que el enfoque de registro requiere un cálculo más intenso. Entonces, tal vez la diferencia es que en una máquina con menos memoria, toString requiere más rondas de recolección de basura, mientras que en una máquina con un procesador más lento, el cálculo adicional del registro sería más doloroso.
También probé un tercer enfoque. Escribí esta pequeña función:
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;
}
Funcionó en 1600 a 1900 milis - menos de 1/3 del enfoque de toString, y 1/10 del enfoque de registro en mi máquina.
Si tuviera un amplio rango de números, podría acelerarlo aún más al comenzar a dividir entre 1,000 o 1,000,000 para reducir el número de veces a través del bucle. No he jugado con eso.
El enfoque más rápido: divide y vencerás.
Suponiendo que su rango es de 0 a MAX_INT, entonces tiene de 1 a 10 dígitos. Puede acercarse a este intervalo utilizando dividir y vencer, con hasta 4 comparaciones por cada entrada. Primero, divide [1..10] en [1..5] y [6..10] con una comparación, y luego cada intervalo de longitud 5 se divide usando una comparación en un intervalo de longitud 3 y uno de longitud 2. El intervalo de longitud 2 requiere una comparación más (total 3 comparaciones), el intervalo de longitud 3 se puede dividir en intervalo de longitud 1 (solución) y un intervalo de longitud 2. Por lo tanto, necesita 3 o 4 comparaciones.
Sin divisiones, sin operaciones de punto flotante, sin logaritmos costosos, solo comparaciones de enteros.
Código (largo pero 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;
}
}
}
Punto de referencia (después del calentamiento de JVM): vea el código a continuación para ver cómo se ejecutó el punto de referencia:
- Método de línea base (con String.length): 2145ms
- Método log10: 711ms = 3.02 veces más rápido que la línea de base
- división repetida: 2797ms = 0.77 veces más rápido que la línea de base
- divide y vencerás: 74ms = 28.99
veces más rápido que la línea 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 faster than baseline");
c = new Chronometer(true);
allMethod3();
c.stop();
System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times faster than baseline");
c = new Chronometer(true);
allMethod4();
c.stop();
System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times faster than 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;
}
De nuevo, punto de referencia:
- Método de línea base (con String.length): 2145ms
- Método log10: 711ms = 3.02 veces más rápido que la línea de base
- división repetida: 2797ms = 0.77 veces más rápido que la línea de base
- divide y vencerás: 74ms = 28.99
veces más rápido que la línea de base
Edición: Después de que escribí el punto de referencia, tomé un adelanto en Integer.toString desde Java 6, y descubrí que 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;
}
Lo comparé con mi solución de dividir y vencer:
- divide y vencerás: 104ms
- Solución Java 6 - iterar y comparar: 406ms
El mío es aproximadamente 4 veces más rápido.
El logaritmo es tu amigo:
int n = 1000;
int length = (int)(Math.log10(n)+1);
NB: solo válido para n> 0.
Forma recursiva facil
int get_int_lenght(current_lenght, value)
{
if (value / 10 < 10)
return (current_lenght + 1);
return (get_int_lenght(current_lenght + 1, value))
}
no probado
Ingrese el número y cree un Arraylist
, y el bucle while registrará todos los dígitos en el Arraylist
. Luego podemos eliminar el tamaño de la matriz, que será la longitud del valor entero que ingresó.
ArrayList<Integer> a=new ArrayList<>();
while(number > 0)
{
remainder = num % 10;
a.add(remainder);
number = number / 10;
}
int m=a.size();
Intente convertir el int en una cadena y luego obtenga la longitud de la cadena . Eso debería obtener la longitud del int .
public static int intLength(int num){
String n = Integer.toString(num);
int newNum = n.length();
return newNum;
}
La solución de Marian se adaptó para números de tipo largos (hasta 9,223,372,036,854,775,807), en caso de que alguien quiera copiarlo y pegarlo. En el programa que escribí esto para números hasta 10000 era mucho más probable, así que hice una rama específica para ellos. De todos modos no hará una diferencia 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;
}
}
}
}
}
La solución de Marian, ahora 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)));
}
Porque podemos.
No puedo dejar un comentario todavía, así que lo publicaré como una respuesta por separado.
La solución basada en logaritmo no calcula el número correcto de dígitos para enteros largos muy grandes, por ejemplo:
long n = 99999999999999999L;
// correct answer: 17
int numberOfDigits = String.valueOf(n).length();
// incorrect answer: 18
int wrongNumberOfDigits = (int) (Math.log10(n) + 1);
La solución basada en logaritmo calcula el número incorrecto de dígitos en enteros grandes
O en lugar de la longitud, puede verificar si el número es mayor o menor que el número deseado.
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);
}
}
}
Otro enfoque de cuerdas. Corto y dulce - para cualquier entero n
.
int length = ("" + n).length();
Podemos lograr esto utilizando un bucle 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+"]");
}
Podrías los dígitos usando división sucesiva por diez:
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);
Solución simple:
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);
}
Su solución basada en String está perfectamente bien, no hay nada "desagradable" al respecto. Debe darse cuenta de que matemáticamente, los números no tienen una longitud, ni tienen dígitos. La longitud y los dígitos son propiedades de una representación física de un número en una base específica, es decir, una cadena.
Una solución basada en logaritmos hace (algunas de) las mismas cosas que la basada en cadenas hace internamente, y probablemente lo hace (de manera insignificante) más rápido porque solo produce la longitud e ignora los dígitos. Pero en realidad no lo consideraría más claro en su intención, y ese es el factor más importante.
Todavía no he visto una solución basada en la multiplicación. Las soluciones basadas en logaritmos, divisiones y cadenas se volverán bastante difíciles de manejar contra millones de casos de prueba, así que aquí hay uno 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;
}
En la base 10, esto funciona porque n se está comparando esencialmente con 9, 99, 999 ... ya que min es 9, 90, 900 ... yn se está restando en 9, 90, 900 ...
Desafortunadamente, esto no es portátil por long
simplemente reemplazando cada instancia de int
debido a un desbordamiento. Por otro lado, da la casualidad de que funcionará para las bases 2 y 10 (pero falla para la mayoría de las otras bases). Necesitará una tabla de búsqueda para los puntos de desbordamiento (o una prueba de división ... 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;
}
Una solución realmente simple:
public int numLength(int n) {
for (int length = 1; n % Math.pow(10, length) != n; length++) {}
return length;
}
Usando java
int nDigits = Math.floor(Math.log10(Math.abs(the_integer))) + 1;
use import java.lang.Math.*;
al principio
Usando c
int nDigits = floor(log10(abs(the_integer))) + 1;
use inclue math.h
al principio
Uno quiere hacer esto principalmente porque quiere "presentarlo", lo que en su mayoría significa que finalmente debe ser "editado" (o transformado de otra manera) explícita o implícitamente de todos modos; antes de que pueda ser presentado (impreso por ejemplo).
Si ese es el caso, intente hacer explícitos los "toString" necesarios y contar los bits.
int num = 02300;
int count = 0;
while(num>0){
if(num == 0) break;
num=num/10;
count++;
}
System.out.println(count);