Vamos a programar #38 - La conjetura de Collatz (Números maravillosos) versión C#.

Hola de nuevo a todos, el día de hoy vamos a hacer un pequeño receso a la programación en Pascal y vamos a ver un poco de C#.

La conjetura de Collatz dice que todos aquellos números son "maravillosos", siempre y cuando al aplicar las siguientes operaciones de forma recursiva, nos resulte 1.

El enunciado dice:

Sea la siguiente operación, aplicable a cualquier número entero positivo:
  • Si el número es par, se divide entre 2.
  • Si el número es impar, se multiplica por 3 y se suma 1.
El problema en si, es fácil, pero al momento de crear la aplicación, debemos de recordar que estamos limitados en el numero máximo que podemos usar. Para solucionarlo, vamos a usar el tipo "BigInteger".
En .net 4.0 se introdujo este nuevo tipo de dato, que permite utilizar enteros de longitud arbitraria, mas que suficiente para poder calcular la conjetura. Actualmente el número mas grande calculado tiene mas de 60 mil millones de cifras.

El código.

El codigo en c# que calcula la conjetura de Colltaz es el siguiente (la lista de controles no se incluye, todo el código fuente lo puedes descargar de dropbox):

using System;
using System.Windows.Forms;
using System.Numerics;
using System.Threading;

namespace ConjeturaDeCollatz
{
	public partial class FrmMain : Form
	{
		private delegate void UpdateListDelegate(string Value);

		private void UpdateList(string Value)
		{
			if (LBResults.InvokeRequired)
			{
				LBResults.Invoke(new UpdateListDelegate(UpdateList), Value);
			}
			else
			{
				LBResults.Items.Add(Value);
			}
		}
		private void CalculateCollatz(string Number)
		{
			BigInteger MyNumber;
			BigInteger.TryParse(Number, out MyNumber);
			while (MyNumber > 1)
			{
				if (MyNumber.IsEven == false)
				{
					MyNumber = MyNumber * 3 + 1;
					UpdateList(MyNumber.ToString());
				}
				else
				{
					MyNumber = MyNumber / 2;
					UpdateList(MyNumber.ToString());
				}
			}
		}
		private void RunWork(string Number)
		{
			Thread DoWork = new Thread(new ThreadStart(() => CalculateCollatz(Number)));
			DoWork.Start();
		}
		public FrmMain()
		{
			InitializeComponent();
		}

		private void BtnStart_Click(object sender, EventArgs e)
		{
			LBResults.Items.Clear();
			RunWork(TxtNumberIn.Text);

		}
	}
}


El código es realmente simple, ya que solo hacemos, para empezar, un bucle "while", que se ejecutará mientras la variable "MyNumber", sea mayor que uno. Después comprobamos si el numero es par, dentro de la estructura del "BigInteger", hay una función llamada "IsEven", la cual sirve para comprobar si un número es par. La utilizamos y si el resultado es "true", hacemos la división entre dos (cómo dice el enunciado), en caso contrario multiplicamos por 3 y le sumamos uno.
Para poder agilizar un poco, todo el proceso, se hace en un "thread" diferente, con lo cual la aplicación no se bloquea.
Por ahora, es todo. Desde mi punto de vista, parece que todos los numero son maravillosos, puesto que al ser impar (que usualmente son números raros), al multiplicar y sumarle uno, en algún punto, siempre nos dará un numero par. Aunque la conjetura no se ha probado (de ahí lo de conjetura), resulta un buen ejercicio para todo programador.
En el siguiente post de C#, agregaremos funciones para obtener más datos que son relevantes para la conjetura, Además, veremos un poco mas a fondo el tipo "BigInteger" y extenderemos el uso de threads para hacer cálculos un poco más "masivos". Cómo de costumbre, el código completo lo dejo en mi dropbox para que lo descargues.

Los leo luego.

No hay comentarios.