Vamos a programar #39 - La conjetura de Collatz (Números maravillosos) Versión Android.

Hola de nuevo a todos, el día de hoy vamos a continuar con la conjetura de Collatz.
En el post anterior de "Vamos a programar", hicimos la versión de C#, cosa que resulto realmente fácil ya que en C# se puede hacer uso del tipo "BigInteger". En java para android, también existe el tipo "BigInteger" y en esta ocasión veremos un poco de cómo usarlo.

El código.

El código que hace funcionar la aplicación de la conjetura de Collatz en java para android es el siguiente:
package com.mdev.collatz;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import java.math.BigInteger;
import java.util.ArrayList;


import static android.R.attr.button;

public class MainActivity extends AppCompatActivity {

	Button BtnCalculate;
	TextView TxtNumberIn;
	ListView LVResultados;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		BtnCalculate = (Button) findViewById(R.id.BtnCalculate);
		TxtNumberIn = (TextView) findViewById(R.id.TXTNumberIn);
		LVResultados = (ListView) findViewById(R.id.LVResults);

		BtnCalculate.setOnClickListener(new View.OnClickListener()
		{
			@Override
			public void onClick(View view) {
				CalculateCollatz(TxtNumberIn.getText().toString());
			}
		});

	}
	private void CalculateCollatz(String Number)
	{
		ArrayList Items = new ArrayList();
		BigInteger MyNumber = new BigInteger(Number);
		while (MyNumber.compareTo(BigInteger.ONE) > 0)
		{
			if (IsEven(MyNumber)) {
				MyNumber = MyNumber.divide(BigInteger.valueOf(2));
				Items.add(MyNumber.toString());
			}else{
				MyNumber = MyNumber.multiply(BigInteger.valueOf(3));
				MyNumber = MyNumber.add(BigInteger.valueOf(1));
				Items.add(MyNumber.toString());
			}
		}
		final ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1,Items);
		LVResultados.setAdapter(adapter);
	}

	private boolean IsEven(BigInteger Number){
		BigInteger Result = Number.remainder(BigInteger.valueOf(2));
		int CompareResult = Result.compareTo(BigInteger.ZERO);
			if(CompareResult == 0)
			{
				return true;
			}else{
				return false;
			}
	}
}

Para empezar crearemos los controles que vamos a necesitar, está aplicación consta únicamente de 4 controles (5 en realidad, puedes revisarlo en el código completo).

  • 1 Textview.
  • 1 EditText
  • 1 Button
  • 1 Listview
Solo vamos a interactuar con los últimos tres pos lo que solo esos son los que crearemos tambien en el código.
Para tratar de simplificar un poco el código, hice lo traté de hacer lo mismo que en c#. Primero, iba a pedir un numero en formato de texto, luego crear una funcion que calcule la conjetura de Collatz y mostrar cada paso que se dio en un "ListView".
La cosa es sencilla, y podemos repetir lo que ya habíamos hecho, pero en java, a diferencia de c#, el tipo BigInteger no es tan simple de manejar.
En Java, el tipo BigInteger dispone de sus operaciones por separado, las comparaciones se deben de hacer desde los métodos contenidos en el tipo BigInteger. Eso quiere decir que si queremos comparar el número "1" con el valor BigInteger "1", no podemos realizarlo porque a diferencia de C#, aquí no se hace una conversión implícita; nosotros debemos de hacerla de forma explicita haciendo uso de los métodos contenidos en el tipo "BigInteger".

Retomando nuestro código, primero veremos la función "IsEven". la función "IsEven" recibe un parámetro del tipo "BigInteger", este, es el numero de cual queremos determinar si es par o no. Para hacerlo, hacemos uso de dos variables; la primera, llamada "Result" del tipo "BigInteger", se crea y se le asigna el valor que resulta del uso del método del parámetro de entrada "Number", el método que se usa es ".remainder()", este método lo que hace, es devolver el residuo de la división entre el numero "Number" y el parámetro que se le asigne; para este caso, debemos de dividir entre dos, pero cómo no se puede usar directamente "2", usamos otro procedimiento del tipo "BigInteger". el método que usamos es "BigInteger.valueOf()", este procedimiento lo que hace, es crear una versión del número que se pasa cómo parámetro en tipo "BigInteger".
Lo anterior se hace para determinar si un número es par o no (hay que recordar que los número pares, son aquellos que al ser divididos entre dos, dan un número entero). El resultado que obtenemos es 1 o 0 (cualquiera de los dos del tipo BigInteger).
Solo nos queda hacer la comparación, si el resultado es "0" entonces el número es par, para hacer la comparación, usamos otro procedimiento más del tipo "BigInteger". Hacemos uso de la función ".compareTo", lo hacemos en la variable resultado y le pasamos cómo parámetro una constante llamada "BigInteger.ZERO"; la constante vale 0. la función regresa un valor del tipo int con cualquiera de los 3 valores posibles:

  1. -1 si el valor es menor que el BigInteger desde el cual se llama.
  2. 0 si el valor es igual que el BigInteger desde el cual se llama.
  3. 1 si el valor es mayor que el BigInteger desde el cual se llama.
Para determinar si la función "IsEven" devuelve "true" o "false", creamos una variable del tipo "int" llamada "CompareResult" a la que le asignamos el valor de la función "Result.compareTo" con parámetro "BigInteger.ZERO".
Si el valor de la variable "result" es "0", la función IsEven devuelve "true", en caso contrario, "false".

El procedimiento "CalculateCollatz", es el encargado de hacer los cálculos, para eso, primero creamos la variable del tipo "BigIntger" llamada "MyNumber". Al usar el constructor del tipo "BigInteger", le podemos pasar un valor del tipo "String", en este caso le asignamos el parámetro "Number", con eso creamos un valor del tipo "BigInteger" con valor del "String" del parámetro.
Después creamos un bucle "while" con la condición "Number" sea mayor que "BigInteger.ONE". Con la función "IsEven", podemos replicar lo que hicimos en c# y dentro del bucle, verificamos si el número es par o no y dependiendo del caso, hacer los cálculos.
Para multiplicar un valor "BigInteger", debemos de hacer uso del método "BigInteger.multiply", este recibe cómo parámetro un "BigInteger" que será el multiplicador y el resultado, sera un valor BigInteger con el valor de la multiplicación. Para dividir un valor "BigInteger", debemos de hacer uso del método "BigInteger.divide", este recibe cómo parámetro un "BigInteger" que será el divisor y el resultado, sera un valor "BigInteger" con el valor de la división. lo mismo para la suma, debemos de hacer uso de "BigInteger.add".
Finalmente creamos un "ArrayAdapter" al que agregaremos todos los pasos que se hicieron y este se asina al control "ListView".

El resultado. Puedes descargar la APK con la aplicación ya compilada, el código completo lo subiré en breve, agregare threads para que la interfaz no se bloquee (aunque así como esta funciona bien), aunque con el código anterior, se cubre toda la parte lógica de la aplicación.

Bien, por ahora es todo.
Los leo luego

No hay comentarios.