Mostrar Mensajes

Esta sección te permite ver todos los posts escritos por este usuario. Ten en cuenta que sólo puedes ver los posts escritos en zonas a las que tienes acceso en este momento.


Mensajes - Kabuto

Páginas: 1 ... 31 32 33 34 35 [36] 37 38 39 40 41 ... 50
701
Comunidad / Re:Presentacion
« en: 14 de Mayo 2020, 23:56 »
Bienvenido.
Siéntete libre de preguntar, responder y aportar lo que quieras.

En la web tienes cursos disponibles para aprender o reafirmar conocimientos.

Un saludo.


702
Comunidad / Re:Uno más
« en: 14 de Mayo 2020, 23:54 »
Bienvenido.
Aquí estamos todos para aprender y ayudar en lo que podamos.

Y yo también voy para 41...  8)

Un saludo.

703
Hola.
Algo importante es conseguir que el método main(), el principal, tenga el menor código posible. Que de una lectura rápida, uno se haga fácilmente una idea de lo que hace el programa y que lógica sigue.

Para ello puede resultar útil declarar variables fuera del main, no necesariamente todas, pero al menos sí las más importantes.
Además, al estar fuera del main, estas variables pasan a formar parte del ámbito global de la clase, lo cuál amplia su visibilidad y nos facilita poder usar métodos para así separar el código en fragmentos menores.
Estos  métodos al estar fuera del main, no podrían tener acceso a las variables que estuvieran dentro del main, ya que su visibilidad se limitaría al interior del main.

Pero si las declaramos fuera, tienen visibilidad absoluta y los métodos pueden interactuar con ellas fácilmente.

Con esto, conseguimos que el main se quede más reducido y legible.
Por ejemplo, la parte donde declaras los arrays ArticuloLitro, ValorArticulo, CodeAlfaNumChar y les das valores.
Son muchas líneas de código que podemos extraer del main y ponerlas en un método separado.


Otra cosa que me he fijado que se puede optimizar, es que cuando pides elegir articulo entre 1 y 3, haces un switch, y en los 3 cases tienes exactamente el mismo código escrito tres veces.
Solo cambia el indice para elegir artículo.
Si el usuario elige 1, tu accedes al 0
Si elige 2, acceder al 1 y si elige 3, accedes al 2....

Si te fijas, no necesitas repetir tres veces el código, solo necesitas restarle -1 a la opción del usuario y así accederías al artículo correcto.

Otra cosa, para el bucle principal usas un while() que se repite 6 veces. Esto es correcto y funciona de maravilla.
Pero si tienes claro que quieres que se repita 6 veces, es mejor usar un bucle for().
Más que nada, porque al leer el código, si un programador ve que has usado un for(), ya tiene la certeza de que el programa está pensado para repetirse un número determinado de veces.
Pero si ve un while(), la tendencia es pensar que se va a ejecutar un número INdeterminado de veces. Luego verá que no es así, pero la primera impresión que se llevará el lector puede ser errónea.

Más cosas. En Java, por convención, los métodos, nombres de variables (incluidos arrays), de objetos... siempre empiezan en minúscula.
Solo los nombres de las clases empiezan con mayúscula.
Por ejemplo Scanner, String, Integer, Object, MiFactura, Programa_empresa....

Por cierto, tampoco es costumbre usar línea de subrayado para separa nombres. En otros lenguajes sí, pero en Java la convención es usar el sistema CamelCase, es decir, cada palabra compuesta hacer que comience con mayúscula.
Así, Programa_empresa sería --> ProgramaEmpresa

Puedes escribirlo como te de la gana, y a Java le va a dar igual. El programa no va a funcionar ni mejor ni peor.
Pero es una de las normas que todos los programadores Java suelen cumplir, entonces, de nuevo, alguien que lea tu código puede confundir el nombre de una variable, con el de una clase, si ambas las escribes con la primera letra en mayúsculas.
Por eso conviene cumplir estas convenciones, por temas de legibilidad.

Dicho esto, así es como podría quedar tu clase aplicando estos cambios (excepto el de las mayúsculas, eso lo dejo a tu criterio).

Código: [Seleccionar]
public class Programa_empresa{

//Variables y objetos de ámbito global
static Random CodeAlfaNumRand = new Random();
static Scanner Input = new Scanner(System.in);
static int ArticuloLitro[] = new int[3];
static int ValorArticulo[] = new int[3];
static int CodeAlfaNumArray = 0, Amplifiart = 0;
static int OPc_1 = 0, FacturasMayores = 0;
static char CodeAlfaNumChar[] = new char[12];
static char CodeAlfaNum[] = new char[6]; //cantidad de elementos del codigo alfanumerico

//Programa principal
public static void main(String args[]){

inicializarArrays(); //Método que inicializa con valores los arrays

for (int j = 0; j <= 5; j++){

declararCodigoAlfa(); //declarar el codigo alfanumerico

do {
System.out.println("\t--- FARMACIA ---\nCual producto desea llevar:");
System.out.println("1: Desinfectante " + ArticuloLitro[0] + "L | Valor: " + ValorArticulo[0]);
System.out.println("2: Desinfectante " + ArticuloLitro[1] + "L | Valor: " + ValorArticulo[1]);
System.out.println("3: Desinfectante " + ArticuloLitro[2] + "L | Valor: " + ValorArticulo[2]);
OPc_1 = Input.nextInt();

if (OPc_1 < 1 || OPc_1 > 3)
System.out.println("No ha selecciona de manera correcta...\n");
else {
System.out.print("Cuantos desea llevar: ");
Amplifiart = Input.nextInt();           
ValorArticulo[OPc_1 - 1] *= Amplifiart; //multiplicar el preico del producto
ArticuloLitro[OPc_1 - 1] *= Amplifiart; //multiplicar cuantos litros hay en total
System.out.println("\t--- FACTURA ---");
System.out.print("Codigo del articulo: ");
for(int i = 0; i < CodeAlfaNum.length; i++){
System.out.print(CodeAlfaNum[i]);
}
System.out.println("\nPrecio total: " + ValorArticulo[OPc_1 - 1]);
System.out.println("Cantidad de litros comprados: " + ArticuloLitro[OPc_1 - 1]);
if (ValorArticulo[0] > 600){
FacturasMayores++;               
}
}

}while(OPc_1 < 1 || OPc_1 > 3);

} //Fin del bucle for

if (FacturasMayores > 1){
System.out.println("Hay " + FacturasMayores + " facturas que pasan de los $600");
}else{
System.out.println("Hay " + FacturasMayores + " factura que pasa de los $600");
}
}

//Métodos de la clase

private static void inicializarArrays() {
ArticuloLitro[0] = 5; //5 Litros
ArticuloLitro[1] = 15; //15 Litros
ArticuloLitro[2] = 25; //25 Litros
ValorArticulo[0] = 150; //valor articulos
ValorArticulo[1] = 300;
ValorArticulo[2] = 425;
//caracteres para el codigo del articulo
CodeAlfaNumChar[0] = 'A';
CodeAlfaNumChar[1] = 'B';
CodeAlfaNumChar[2] = 'C';
CodeAlfaNumChar[3] = 'D';
CodeAlfaNumChar[4] = 'E';
CodeAlfaNumChar[5] = 'F';
CodeAlfaNumChar[6] = 'G';
CodeAlfaNumChar[7] = '0';
CodeAlfaNumChar[8] = '1';
CodeAlfaNumChar[9] = '2';
CodeAlfaNumChar[10] = '3';
CodeAlfaNumChar[11] = '4';
}

private static void declararCodigoAlfa() {
for(int i = 0; i < CodeAlfaNum.length; i++){
CodeAlfaNumArray = CodeAlfaNumRand.nextInt(12);
CodeAlfaNum[i] = CodeAlfaNumChar[CodeAlfaNumArray];
}
}
}

Como puedes ver, el main se ha quedado mucho más reducido. Y el código es casi el mismo. Solo se ha reducido el código del switch, que ya no es necesario repetirlo.
El resto sigue estando ahí, solo que fuera del método main.

Bien, revisada la estética del programa, ahora quiero hacerte notar una cosa sobre la lógica, que me parece que no es correcta.
Cuando se selecciona un artículo y su cantidad, para calcular el precio y la cantidad que se lleva, estás modificando los valores en los arrays de artículos, porque haces la multiplicación directamente sobre ellos.
Lo marco en rojo.

Citar
               System.out.print("Cuantos desea llevar: ");
               Amplifiart = Input.nextInt();           
               ValorArticulo[OPc_1 - 1] *= Amplifiart; //multiplicar el preico del producto
               ArticuloLitro[OPc_1 - 1] *= Amplifiart; //multiplicar cuantos litros hay en total

Esto produce un efecto indeseado. Y es que la primera vez que se muestran en pantalla las opciones, salen bien. Garrafas de 5L, de 15L y de 25L
Pero al hacer una compra, la siguiente vez que se muestran, estos valores han sido modificados por la compra anterior.
Mira:
Citar
   --- FARMACIA ---
Cual producto desea llevar:
1: Desinfectante 5L | Valor: 150 //Valor correcto ;)
2: Desinfectante 15L | Valor: 300
3: Desinfectante 25L | Valor: 425
1
Cuantos desea llevar: 1000
   --- FACTURA ---
Codigo del articulo: C0D4AC
Precio total: 150000
Cantidad de litros comprados: 5000
   --- FARMACIA ---
Cual producto desea llevar:
1: Desinfectante 5000L | Valor: 150000 //WTF!! :0
2: Desinfectante 15L | Valor: 300
3: Desinfectante 25L | Valor: 425

Habría que cambiar esa lógica. El cálculo del importe y guardado de este no debería hacerse en los arrays de artículos. Estos arrays deberían ser intocables.

Dale un par de vueltas a ver que se te ocurre.

Un saludo y muchas gracias por participar en el foro

704
Aprender a programar desde cero / Re:Visual Basic - Consulta
« en: 11 de Mayo 2020, 17:12 »
La foto es muy pequeña y no se ve lo que tienes escrito realmente.

Por otra parte, prueba a escribir "a mano" en lugar de copiar y pegar.
A veces al copiar y pegar, algunos IDE añaden caracteres invisibles o mal interpretan algunos símbolos.
Por ejemplo, las comillas -> " " , a mi me ha pasado alguna vez que no se han copiado bien.

705
Hola.
Muevo tu mensaje a otra sección más acorde. Donde publicaste inicialemente es para presentaciones y sugerencias.

Esto que preguntas, me ha recordado un práctica que hice algún tiempo (que no llegué a terminar, como casi todo lo que hago xD) donde simulaba una cartelera de cine, y guardaba información de películas, incluida una imagen con la portada de la película.
Estos objetos los serializaba para guardarlos en disco y recuperarlos al iniciar el programa.

No se si podría ser aplicable en tu caso, es cuestión de probralo.
La imagen, la guardaba en un array de bytes.

Mira, estos eran los atributos de la clase. Marco en negrita donde se guardaba la imagen.

Citar
public final class Pelicula implements Serializable{
   
   private String titulo;
   private String director;
   private String anio;
   private String sinopsis;
   private String genero;
   private Integer entradasVendidas;
   private Double recaudacion;
   private byte[] portada;

Para convertir la imagen en un array de bytes, usaba el siguiente método, que recibe un objeto File que apunta al fichero de la imagen.
Citar
   public void setPortada(File imagen) {
      portada = new byte[(int)imagen.length()];
      try {
         FileInputStream fis = new FileInputStream(imagen);
         fis.read(portada);
         fis.close();
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }

Para el proceso inverso, es decir, ese array de bytes volver a construir una imagen, usaba este otro método que devolvía un objeto Image.
En este método la devuelvo reescalada a un determinado tamaño para que me coincida con un JPanel que usaré para mostrarla, pero no es necesario, eso ya depende de tu caso.
Citar
   public Image getPortada() {
      Image imagen = null;
      ByteArrayInputStream bis = new ByteArrayInputStream(portada); //portada es el array de bytes
      try {
         imagen = ImageIO.read(bis);
      } catch (IOException e) {
         JOptionPane.showMessageDialog(null, "Error recuperando portada desde el array de bytes",
               "Pelicula.getPortada()", JOptionPane.ERROR_MESSAGE);
         e.printStackTrace();
      }
      return imagen.getScaledInstance(250, 382, Image.SCALE_SMOOTH);
   }

De este modo, con ObjectOutputStream lo guardaba en disco, y con ObjectInputStream lo recuperaba al iniciar el programa.


Este objeto Image que devuelve este último método, yo luego lo "pintaba" en una clase que hereda de Jpanel, y así se mostraba la imagen en pantalla.

Citar
   private class PanelImagen extends JPanel {
      private Image imagen;

      public PanelImagen() {
         setBackground(Color.DARK_GRAY);
         setPreferredSize(new Dimension(250, 382));
         setMaximumSize(new Dimension(250, 382));
      }

      public void setImagen(Image img) {
         imagen = img;
         repaint();
      }

      public void reset() {
         imagen = null;
         repaint();
      }

      @Override
      public void paintComponent(Graphics g) {
         super.paintComponent(g);
         g.drawImage(imagen, 0, 0, 250, 382, this);
      }
   }

No se darte más detalles al respecto, porque es algo que hice hace mucho tiempo, algo que de hecho no sabía hacer y tras investigar por la red di con esta solución.
Ya te digo que ni recordaba que había empezado esta práctica, la tenía olvidada y tu consulta me la ha hecho recordar.

Mira a ver si puedes implementarlo en tu código y nos cuentas.

Un saludo.

706
00 es lo mismo que 0, es decir, es un int.

Java lo acepta, porque lo que hace es transformar automáticamente ese int a double, y no pasa nada.

Pero sí, es más adecuado, usar 0.0, más que nada porque al leer el código queda patente que se está trabajando con números reales.

Además se puede usar 0d , cuando es double, y también 0f si es float.

Pero vamos, es por cuestión de legibilidad del código. Java sí admite que inicialicemos un valor double con un int, porque lo transformará.

Lo que Java no admitiría es al contrario, a una variable int inicializar con un valor double como 0.0.
No lo admitiría porque considera que transformar eso a int es "perder información", porque se pierde la parte decimal, así que automáticamente no lo admite, a no ser que el programador fuerce el casteo

707
Aprender a programar desde cero / Re:AYUDA CON UN TEMA
« en: 04 de Mayo 2020, 18:27 »
Muevo el tema a otra sección, ya que donde se había publicado es una sección para presentaciones y sugerencias.

Para calcular la mediana tienes que ordenar aritméticamente los números que tengas. La mediana será el valor que esté en la posición central.

Por ejemplo, tenemos estos 5 números: 1.3, 6.2, 8.0, 5.3 y 5.1
Si los ordenamos, el valor que queda en el centro, es la mediana:
1.3, 5.1, 5.3, 6.2, 8.0

¿Y si tenemos una cantidad par de números? Entonces no habrá un número que quede exactamente en el centro:
1.3, 5.1, 6.2, 8.0

En ese caso, se cogen los dos centrales, y se calcula su media aritmética

1.3, 5.1, 6.2, 8.0

5.1 + 6.2 / 2= 5.65


Bien, esa es la teoría. Si quieres hacerlo mediante un código de programación, comienza tú un programa y te ayudamos a completarlo.
Ve por partes, comienza por un programa que sea capaz de ordenar un array de números.

Cuando eso funcione, ya se irá pensando como hacer el resto.

708
Aprender a programar desde cero / Re:Diferencia entre fechas
« en: 03 de Mayo 2020, 18:14 »
Seguramente.
Si se consideran que todos los meses duran 30 días, lo cuál es falso, es imposible que de resultados acordes con la realidad.

Esa regla de los 30 días es para simplificar, pues si se quisiera ser exquisito en los cálculos, la cosa se complicaría mucho: meses de 30 días, otros de 31, está Febrero que es de 28.. menos en años bisiestos que entonces es 29...

Al final se desvirtúa la intención del ejercicio, que es enseñar a programar, no a ser astrólogo xDD

Un saludo.

709
Aprender a programar desde cero / Re:Diferencia entre fechas
« en: 02 de Mayo 2020, 17:50 »
¿Aquí querías poner meses + 30, o más bien sería meses * 30?

Citar
if (Year_2 > Year || Year > Year_2){
    DateMinus = (Day - Day_2) - ((Month - Month_2) + 30) - (((Year - Year_2) * 365));

710
Es habitual liarse con el tema del contexto estático y "no estático".

El método main, que pertenece a tu clase EjemploHilos, es estático:

Citar
public static void main(String[] args)

Esto implica dos cosas:
1- No es necesario instanciar un objeto de la clase EjemploHilos para poder ejecutar este método main. Precisamente por eso los main son siempre estáticos.

2- Al ser un método que está en un "contexto estático" no puede acceder a variables, métodos, clases... que no estén también en un contexto estático.

Y este es el problema que tienes. Las clases internas HiloA, HiloA , etc... no son estáticas, así que el main no puede acceder a ellas.

¿Cómo solucionarlo? Lo más directo y sencillo, es declarar todas esas clases también como estáticas. Y asunto resuelto.

Citar
public static class HiloA implements Runnable{

711
A ver, tenemos una clase Cliente, con sus atributos, getters y setters.

Código: [Seleccionar]
public class Cliente {

private String dni;
private String nombre;
private String especialidad;

public Cliente(String dni, String nombre, String especialidad) {
this.dni = dni;
this.nombre = nombre;
this.especialidad = especialidad;
}

public String getDni() {
return dni;
}

public void setDni(String dni) {
this.dni = dni;
}

public String getNombre() {
return nombre;
}

public void setNombre(String nombre) {
this.nombre = nombre;
}

public String getEspecialidad() {
return especialidad;
}

public void setEspecialidad(String especialidad) {
this.especialidad = especialidad;
}

}

Bien, luego en una clase main declaramos un array de clase Cliente con 10 elementos.

Al inicializar este array, sus 10 elementos tienen valor null.
Entonces, en esa opción 1 de crear nuevo Cliente, lo que hay que hacer es:
- Pedir datos para crear Cliente: dni, nombre y especialidad
- Con esos datos, creamos un nuevo objeto Cliente.
- Buscar un hueco libre en el array. ¿Cómo?
Pues con un bucle lo recorremos y buscamos una posición que tenga valor null.
Si encontramos dicha posición, guardamos su indice y luego lo usamos para meter ahí el nuevo Cliente que hemos creado.
Si no se encuentra ninguna posición null, es que el array ya está lleno, así que no se puede guardar el nuevo Cliente.

El código podría ser como este. Pruébalo y verás que cada nuevo Cliente se va guardando en la posición 0, luego, 1, 2, 3... hasta la posición 9.

A partir de ahí, el array está lleno y ya no se pueden guardar más Clientes.

Código: [Seleccionar]
public class TestCliente {

private static Scanner teclado = new Scanner(System.in);
private static Cliente[] clientes = new Cliente[10];

public static void main(String[] args) {

int opc = 0;
do {
System.out.println("\n\t\tMENU OPCIONES");
System.out.println("[1] -- Nuevo Cliente");
System.out.println("[9] -- SALIR");
System.out.print("Elija opcion: ");
opc = Integer.parseInt(teclado.nextLine());

switch(opc) {
case 1:
nuevoCliente();
break;
case 9:
System.out.println("\nFIN DE PROGRAMA");
break;
default:
System.out.println("\nOpción inválida.");
}

}while(opc != 9);

}

private static void nuevoCliente() {
//Pedimos datos para crear un CLiente
System.out.print("\nDNI: ");
String dni = teclado.nextLine();
System.out.print("Nombre: ");
String nombre = teclado.nextLine();
System.out.print("Especialidad: ");
String especi = teclado.nextLine();
//Creamos Cliente
Cliente nuevoCliente = new Cliente(dni, nombre, especi);
//Buscamos posicion libre en el array
int huecoLibre = -1;
for (int i = 0; i < clientes.length && huecoLibre == -1; i++) {
if (clientes[i] == null) //Hemos encontrado hueco libre
huecoLibre = i; //Guardamos posicion libre, esto ademas pone fin al bucle
}
//Comprobamos si hemos encontrado hueco libre
if (huecoLibre == -1)
System.out.println("No hay espacio disponible para guardar el nuevo Cliente.");
else {
clientes[huecoLibre] = nuevoCliente;
System.out.println("Nuevo Cliente se ha guardado en la posición: " + huecoLibre);
}
}

}

712
Comunidad / Re:Presentación
« en: 28 de Abril 2020, 18:10 »
Bienvenido.
Nunca es tarde para aprender cosas nuevas. De hecho a ciertas edades, tenemos las cabezas más centradas y dispuestas para nuevas retos.

Yo tengo tu edad y hace poco me he propuesto aprender a hacer juegos con Unity, aunque yo sí trabajo estos días, así que el tiempo escasea y el progreso es leeento.

Un saludo.

713
Aprender a programar desde cero / Re:Comprensión de un código
« en: 27 de Abril 2020, 17:12 »
El operador módulo te da el resto final.
Por ejemplo, mira la división de esta imagen:




Si en el código hacemos un 243 % 5, el resultado que nos dará sera 3

Un ejemplo muy habitual en programación para practicar el operador módulo es un programa que reciba un número y diga si es par o impar.
La forma de saber si un número es par, es dividir entre 2 y comprobar si el resto es 0.
Es decir, si tenemos el número guardado en una variable llamada num, pues preguntaríamos esto:

Código: [Seleccionar]
if (num % 2 == 0)
    System.out.println("Es par");
else
    System.out.println("Es impar);

De este ejemplo, podemos deducir que también podemos usarlo para saber si un número es múltiplo de otro.
De nuevo, imagina que tenemos num1 y num2. Si al dividir num1 entre num2, el resto es cero, significa que num1 es múltiplo de num2.

Mayormente, el resto es útil en aplicaciones matemáticas como por ejemplo una técnica para dividir polinomios (Teorema del residuo/resto).


Pero hay también algún que otro uso curioso.

Por ejemplo en España, los DNI/NIF para identificar a cada ciudadano consta de una cadena con un número de 8 cifras y una letra.
Esa letra no es al azar, depende del resto de ese número al dividir entre 23.

En el curso de Java se propone resolver este ejercicio en Java.
Esta más pensado para aprender a  usar arrays, pero bueno, puedes intentarlo.



714
Comunidad / Re:Hola
« en: 27 de Abril 2020, 16:40 »
Bienvenido.
Genial que se una más gente con ganas de ayudar y compartir lo poco o mucho que sepan.

Un saludo.

715
Aprender a programar desde cero / Re:JAVA pagar aciertos 1 cifra
« en: 25 de Abril 2020, 13:06 »
Deberías intentar hacerlo usando String y no int.

Tenemos la tendencia a que cuando trabajamos con números, pensamos que lo correcto es escoger un tipo de dato numérico como int.
Pero solo deberíamos hacerlo cuando necesitemos hacer operaciones aritméticas con esos números: sumar, restar, dividir, contar, acumular, potenciar,...

Para casos como números de teléfono, números DNI/cédula, códigos postales, placas de vehículos..., números de lotería..., etc...
Es mejor usar String.
Sobre todo si vamos a necesitar comparar los caracteres que componen ese número por separado, sustituirlos, añadirlos... y cosas así, va a resultar mucho más fácil con la clase String que no con int/Integer.


Si no quieres usar String, otra opción es usar un array de 4 int, aunque esto te obligaría a pedir los 4 números de apuesta por separado.

Trabajar directamente con un int te va a obligar a usar mucho código y romperte la cabeza.
Y además NUNCA vas a conseguir que por ejemplo 45 te lo transforme en 0045... porque son exactamente el mismo número y aritméticamente los 0 a la izquierda no tienen ningún valor.
Un int no guarda caracteres, guarda un valor aritmético.
Si quieres que un 45 tenga 4 caracteres complementando con ceros a la izquierda, tendrás que usa un String o un array.

Inténtalo, si necesitas más ayuda porque no conoces bien la clase String y sus numerosos métodos, dilo y te ayudamos en lo que sea.


716
Aprender a programar desde cero / Re:Comprensión de un código
« en: 22 de Abril 2020, 17:47 »
Este es un tema más de matemáticas que de programación.
Por cierto, el código de ejemplo no es correcto, las horas no se están calculando bien porque hace directamente módulo entre 24 sobre las horas totales. Y no es correcto.

Pero vamos a verlo poco a poco.


Supón que HorasTotales = 200

Y queremos saber a cuantas semanas, días y horas equivalen esa cantidad de horas.

Si una semana tiene 168 horas, pues es evidente que si dividimos esas HorasTotales entre 168, nos dirá a cuantas semanas equivalen

200 / 168 = 1,19

Vale, con ese resultado sabemos que 200 horas equivale a 1 semana y un poco más.
Esa parte decimal, el 0,19, no es una semana completa, pero equivale a cierta cantidad de días y de horas.
Pero, ¿como transformamos ese 0.19 en días? ¿Dividimos entre 24 porque un día tiene 24 horas?

0,19 / 24 = 0.007916

Buff... estamos obteniendo valores decimales muy pequeños que no nos dicen gran cosa.

Es evidente que el razonamiento matemático que estamos siguiendo no es el bueno.

No podemos coger la parte decimal y seguir haciendo cálculos con ella.

Lo que tenemos que coger es el "resto", que como su propio nombre indica, es lo que "resta" sin computar tras haber hecho la división, es lo que realmente ha sobrado.

Para obtener el resto se usa el operador "módulo", que en muchos lenguajes (no todos) se representa con el símbolo %.
Ojo porque puede confundirnos y pensar que estamos calculando porcentajes. Pero no es así, en Java ese operador lo que nos da es el resto.

Entonces, recapitulemos.
Si hacemos una "división entera" de HorasTotales entre 168 nos dirá las "semanas enteras" equivalentes.
En el código que has puesto no se ve, pero la variable Semanas seguramente será de tipo int. Esto fuerza a que la división sea "entera", es decir, esa variable no va a recoger la parte decimal, solo la parte entera.

Así que:
Semanas = 200 / 168 = 1

Ya tenemos calculado el valor de Semanas.
Ahora queremos calcular el valor de Dias.
Como hemos dicho, necesitamos el resto resultante de dividir entre 168, el valor que nos daba las semanas.
Para ello usamos el operador módulo:

Dias = 200 % 168 = 32

Tenemos el valor 32, pero eso es lo que ha sobrado al transformar en semanas.
Eso que sobra, ahora hay que transformarlo en días

32 / 24 = 1,33333

Similar a como ocurría antes, tenemos 1 día entero y un poco más.
Ese poco más, el 0.3333, no da para un día, pero si equivaldrá a unas horas que hay que calcular.
Así que una vez más, habrá que obtener el resto, que nos indicará las horas que han sobrado.
Es aquí donde fallaba el código que has puesto de ejemplo. Para las horas no se hace mod 24 directamente sobre las hora totales, si no sobre el resto obtenido al dividir entre 168

Recapitulación final:
Semanas = 200 / 168 = 1
Dias = 200 % 168 / 24 = 1
Horas = (200 % 168) % 24 = 8

Según esto, 200 horas equivalen a 1 semana, 1 día y 8 horas.
¿Es correcto?
Pues a ver...

1 semana = 168 horas
       1 dia =   24 horas
       resto =     8 horas
                  ----------
                   200 horas


Esto, escrito así rápido en Java podría ser:

Código: [Seleccionar]
public class CalculaSemanas {

public static void main(String[] args) {

Scanner teclado = new Scanner(System.in);

System.out.print("Horas totales: ");
int horasTotal = teclado.nextInt();

int semanas = horasTotal / 168;
int dias = horasTotal % 168 / 24;
int horas = (horasTotal % 168) % 24;

System.out.println("\n" + horasTotal + " horas equivalen a");
System.out.println("- Semanas: " + semanas);
System.out.println("- Dias: " + dias);
System.out.println("- Horas: " + horas);

teclado.close();
}

}

Y si probamos a ejecutarlo en pantalla nos da este resultado:
Citar
Horas totales: 200

200 horas equivalen a
- Semanas: 1
- Dias: 1
- Horas: 8

Y bueno, espero haberme explicado bien.

Como digo, esto es más matemáticas que programación. Hay que entender como obtener el resto de la división y qué se puede calcular con él.

Pregunta lo que necesites. Y si alguien sabe explicarlo mejor que yo, por favor, que lo haga y todos aprendemos más.

Un saludo.

717
No, para nada.

La clase Scanner también se puede usar para leer ficheros de texto, pero en este caso, puede ser preferible usar la clase BufferedReader que sí da un rendimiento más óptimo.

Pero vamos, hablamos de milisegundos, lo cuál no tiene que preocuparnos especialmente cuando estamos aprendiendo a programar, y no ha rascarle milisegundos al tiempo.

718
Sí.

Siempre que leas un dato numérico con nextInt(), nextDouble(), nextFloat(), nextByte()....  puedes estar seguro que la siguiente lectura con nextLine() fallará.

Por eso mejor hacer las lecturas como propuse, para evitar el problema.

719

Mmm... Vale, creo que lo he captado.
Entonces, lo que está pasando ahí es que al tener de "denominador" las entradas numéricas estas se le suelen tener más preferencia que las de datos String, omitiendo el paso a que la entrada del valor String ya se haya considerado "ocupada".
No exactamente, no es un tema de preferencias.

Mira, si yo introduzco un número, por ejemplo el 45, tras pulsar enter en  la memoria del ordenador tenemos esto:

45\r

Ese \r es el carácter retorno de carro.

Si eso que está en memoria lo recoge un nextInt(), solo va a coger lo que le interesa, los números.
Así que en memoria tenemos esto ahora:
\r

Si ahora pedimos a nextLine() que entre en acción, porque el usuario va a teclear una línea String, se va a encontrar ese \r en la memoria y va a creer que el usuario ya ha pulsado la tecla enter, cuando en realidad no ha tenido ocasión de pulsar nada.

En tu código, si volvemos a utilizar un único Scanner para todo el programa, es este el problema que ocurre.
Cuando falla el login y se le pregunta al usuario si quiere crear una nueva cuenta, estamos leyendo su respuesta con un nextInt().

Ese nextInt() va a dejar un \r en la memoria, en el flujo de datos del Scanner. Por eso en la siguiente iteración del bucle, donde un nextLine() espera recibir un "nombre de usuario", no se va a poder introducir porque ese \r "olvidado" va a finalizar la inserción del nombre sin tiempo a teclear nada.

Citar
public class Practica_1{
      public static void main(String args[]){
         int OPC_CrearCuenta = 0;
         boolean IntentoLogin = false;
         String Usuario, PassW, UsuarioL, PassWL;
         Scanner Input = new Scanner(System.in); //Un único Scanner
        
         do{
            //registro
            System.out.println("--- INICIO DE SESION ---\n\tRegistro");
            System.out.print("Nombre de ususario: ");
            Usuario = Input.nextLine(); //Este nextLine() fallará en la siguiente repetición
            System.out.print("Contraseña: ");
            PassW = Input.nextLine();
        
            //inicio
            System.out.println("--- INICIO DE SESION ---\n\tIniciar");
            System.out.print("Nombre de ususario: ");
            UsuarioL = Input.nextLine();
            System.out.print("Contraseña: ");
            PassWL = Input.nextLine();
        
        
            //ver si los datos coinciden
            if (UsuarioL.equals(Usuario) && PassWL.equals(PassW)){
               System.out.println("Has ingresado correctamente\n\tBienvenido " + Usuario);
               IntentoLogin = false;
            }else{
               System.out.println("Has ingresado el usuario de manera incorrecta");
               System.out.println("¿Deseas crear una nueva cuenta?\n1: SÍ | 2: NO");
               OPC_CrearCuenta = Input.nextInt(); //Estos nextInt() dejarán carácter \r en memoria que entorpecerán siguientes lecturas con nextLine()
            
               while(OPC_CrearCuenta > 2 || OPC_CrearCuenta < 1){ //mientras que el ususario no de la respuesta correcta
                  System.out.println("No has ingresado de la manera correcta. . .");
                  System.out.println("¿Deseas crear una nueva cuenta?\n1: SÍ | 2: NO");
                  OPC_CrearCuenta = Input.nextInt();
               }
               //en el caso de crear cuenta
               if (OPC_CrearCuenta == 1){
                  System.out.println("Has decidido crear una nueva cuenta. . .");
                  IntentoLogin = true;
               }else if (OPC_CrearCuenta == 2){
                  System.out.println("Has decidido no crear la cuenta. . .");
                  IntentoLogin = false;
               }
            }
         }while(IntentoLogin == true);
      }
   }


Podemos solucionarlo tal y como dije en el mensaje anterior. Hacemos todas las lecturas con nextLine(), para evitar dejar carácter \r olvidados.
Y si lo que necesitamos es un valor numérico, lo parseamos a Integer, a Double o a lo que haga falta.

Citar
public class Practica_1{
      public static void main(String args[]){
         int OPC_CrearCuenta = 0;
         boolean IntentoLogin = false;
         String Usuario, PassW, UsuarioL, PassWL;
         Scanner Input = new Scanner(System.in);
        
         do{
            //registro
            System.out.println("--- INICIO DE SESION ---\n\tRegistro");
            System.out.print("Nombre de ususario: ");
            Usuario = Input.nextLine();
            System.out.print("Contraseña: ");
            PassW = Input.nextLine();
        
            //inicio
            System.out.println("--- INICIO DE SESION ---\n\tIniciar");
            System.out.print("Nombre de ususario: ");
            UsuarioL = Input.nextLine();
            System.out.print("Contraseña: ");
            PassWL = Input.nextLine();
        
        
            //ver si los datos coinciden
            if (UsuarioL.equals(Usuario) && PassWL.equals(PassW)){
               System.out.println("Has ingresado correctamente\n\tBienvenido " + Usuario);
               IntentoLogin = false;
            }else{
               System.out.println("Has ingresado el usuario de manera incorrecta");
               System.out.println("¿Deseas crear una nueva cuenta?\n1: SÍ | 2: NO");
               OPC_CrearCuenta = Integer.parseInt(Input.nextLine());
               //Leemos un String con nextLine() y parseamos a Integer.
            
               while(OPC_CrearCuenta > 2 || OPC_CrearCuenta < 1){ //mientras que el ususario no de la respuesta correcta
                  System.out.println("No has ingresado de la manera correcta. . .");
                  System.out.println("¿Deseas crear una nueva cuenta?\n1: SÍ | 2: NO");
                  OPC_CrearCuenta = Integer.parseInt(Input.nextLine());
               }
               //en el caso de crear cuenta
               if (OPC_CrearCuenta == 1){
                  System.out.println("Has decidido crear una nueva cuenta. . .");
                  IntentoLogin = true;
               }else if (OPC_CrearCuenta == 2){
                  System.out.println("Has decidido no crear la cuenta. . .");
                  IntentoLogin = false;
               }
            }
         }while(IntentoLogin == true);
      }
   }


De este modo, con un único Scanner, podemos hacer lecturas de cualquier tipo tranquilamente.

Un saludo.

720
Sin ver el código original no sabría decirte que ocurre.

Sí puedo comentar que un problema muy habitual es que, tras leer un dato numérico con nextInt(), nextFloat(), etc....
Si después intentamos leer un String con nextLine(), esta lectura fallará.

Por ejemplo:

Citar
System.out.print("Introduce tu numero: );
int numero = input.nextInt();

System.out.print("Introduce tu nombre: );
String nombre = input.nextLine();

En este código no se podrá introducir el nombre, se quedará como una cadena vacía.
¿Por qué?
Porque cuando introducimos el número, tecleamos el número y además pulsamos la tecla intro para terminar la entrada.
Esa tecla intro, aunque no lo veamos, genera un carácter especial llamado "retorno de carro".

Entonces, nextInt() va a coger del input aquello que le sirva para construir un valor Integer, así que cogerá los números tecleados por el usuario, pero no cogerá el carácter retorno de carro.

Ese carácter no desaparece, se queda en el flujo de datos del input.

Luego, viene la lectura con nextLine(). Este método cogerá todo lo necesario para construir una línea completa. Para ello, necesita recoger también el carácter retorno de carro, que es lo que completa y finaliza una línea.

¿Que ocurre?
Que al pedir el nombre, nextLine() se encuentra que en el flujo de datos ya hay un retorno de carro, el que nextInt() dejó abandonado. Entonces nextLine() se confunde, piensa que el usuario ya ha terminado de teclear el nombre y da por finalizada la entrada de datos.

Por eso, siempre que intentemos leer un String con nextLine(), después de haber leído un valor numérico, esa lectura fallará.
No se si será este tu caso.

Por supuesto, tiene solución.

Una es que al terminar de leer datos numéricos, hagamos un nextLine() para eliminar cualquier retorno de carro que haya quedado en el input.
No hace falta recogerlo en ninguna variable, simplemente invocamos al método:
Citar
System.out.print("Introduce tu numero: );
int numero = input.nextInt();
input.nextLine() //Eliminamos carácter retorno de carro del flujo de datos

System.out.print("Introduce tu nombre: );
String nombre = input.nextLine();


Otra solución, es hacer TODAS las lecturas usando siempre nextLine().
Entonces, si queremos un dato numérico, lo que hacemos es parsear(transformar) el String que nos ha dado nextLine(), en el tipo de dato numérico que deseamos:

Citar
System.out.print("Introduce tu numero: );
int numero = Integer.parseInt(input.nextLine()); //Leemos String y parseamos a Integer

System.out.print("Introduce tu nombre: );
String nombre = input.nextLine();

Cualquier forma es válida, pero quizás sea mejor esta última, por dos motivos:

1- Más adelante, cuando hagas interfaces gráficas con ventanas, botones, campos de texto... los datos SIEMPRE los vas a recibir como un String.
Así que siempre vas a tener que parsear al tipo de dato numérico que necesites.
Por lo tanto, no viene mal ir cogiendo ya la costumbre.

2- Esta forma de leer datos, directamente como String para automáticamente parsear a valor numérico, es la forma habitual de leer datos en otros lenguajes que seguramente algún día querrás meterles mano como C#.
Así que también habrás adquirido ya esta costumbre.


Insisto, no se si era este tu problema. Si pudiéramos ver el código quizás te pudiéramos informar mejor.

Un saludo.

Páginas: 1 ... 31 32 33 34 35 [36] 37 38 39 40 41 ... 50

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".