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.

Learning Machine #6 - Bucle while.

Hola de nuevo a todos, el dia de hoy vamos a ver un poco mas de programacion en pascal. Hoy toca ver cómo se usa el bucle "while".


El bucle "while" cómo su nombre lo indica, es una palabra reservada que sirve para indicar que queremos hacer un proceso y que este se repita hasta que cierta condición se cumpla.
Supongamos que queremos comprobar un numero que el usuario escriba con un numero que nosotros tengamos almacenados en una variable, para evitar que se la pase todo el día escribiendo números, vamos a darle un numero limitados de intentos; supongamos 5.
Para llevar a cabo la tarea mencionada antes, podemos usar código como el que sigue:

program Bucle;
uses crt;
var Oportunidades, MiNumero, TuNumero : integer;
begin
 MiNumero := 64;
 clrscr;
 while Oportunidades <= 5 do
 begin
  writeln('Ingresa un numero');
  readln(TuNumero);
  if TuNumero <> MiNumero then
   Oportunidades := Oportunidades + 1
  else
   break;
 end;
 writeln('Fin del programa');
 readln();
end.

Para empezar veamos cómo es que funciona la palabra reservada while. Esta palabra va seguida de una condición, en el código anterior, la condición es: "Oportunidades <= 5" después sigue la palabra reservada "do". todo el bloque de código que se usa debe ir en medio de las palabras reservadas "begin" y "end;". Todo el código que se quiera ejecutar debe de ir en esta sección. Una representación de cualquier bucle "while", puede ser el siguiente:

while "Condicion No se cumple" do
begin
 { ... }
 { ... }
 { ... }
 { ... }
end

Algo que se debe de tener muy en cuenta, es el cómo se plantea la condición. Al ir avanzando linea por linea, cuando en la ejecución se encuentra "while" evaluara la expresión y si al hacerlo esta ya se cumple, simplemente avanzara hasta la linea donde se encuentre el "end" del cierre del bucle.
Para el caso del primer código,  primero le asignamos un valor a la variable "MiNumero" y después viene el bucle "while" con la condición que mientras la variable "Oportunidades" sea menor o igual que 5, haga lo que está dentro del bucle.
Adentro del bucle, le vamos a preguntar un numero  al usuario y lo almacenaremos en la variable "TuNumero", luego compararemos la variable "TuNumero" con la variable "MiNumero" y si son diferentes, a la variable "Oportunidades" le sumaremos 1. Si escribimos 5 veces un numero que no sea 64, llegaremos al final de la ejecución, pero si solo escribimos el numero 64, esto nos llevara al final del programa, porque la palabra reservada "break", sirve para salir del bucle sin importar que la condición se haya cumplido o no, en el caso anterior, en el "if", solo hay dos posibles vias, una es cuando "TuNumero" y "MiNumero" son diferentes y la otra es cuando el número es igual, cuando se escribe 64 no tiene sentido que le sigamos preguntando cual es nuestro numero porque ya lo ha averiguado, entonces hacemos uso de "break" y con eso iremos al final del programa.
Solo para probar que funciona, puedes cambiar el "<=" por ">=". Con esto, el programa ira directamente a la penúltima linea ("readln"), porque se habrá brincado todo el bucle.

Y bien, por ahora es todo, la semana que viene continuaremos con mas de la programación en Pascal.

Learning Machine #5 - Estructura de control if y else.

Hola de nuevo a todas, el día de hoy vamos a  continuar con el aprendizaje del lenguaje de programación Pascal. Hoy toca ver la estructura de control if.

Parte fundamental de cualquier programa, es tomar una decisión en base a algo, en el caso de la programación, podemos por ejemplo: decidir si hacer algo o no si un numero es tan grande; o tan pequeño en comparación a otro, juntar todas las cosas que el usuario escriba que empiecen por una letra.


IF

La estructura de control "if" sirve para redireccionar el flujo de un programa, para hacerlo, primero hará una comprobación y si el resultado es cierto, el programa ejecutará cierto código.

Para usar "if" en Pascal, primero hay que escribir la palabra reservada "if", depues viene la parte de la comprobación lógica en la cual si el resultado es "verdadero", ejecutara código dentro de la instrucción if. una vez escrita la condición, debemos de incluir la palabra reservada "then".

Para hacer las comparaciones disponemos de los siguientes simbolos de comparacacion:

  • < Menor que
  • <= Menor o igual que 
  • > Mayor que
  • >= Mayor o igual que
  • = Igual que
  • <> Distinto que
Los símbolos anteriores los usaremos de la siguiente forma, supongamos que queremos comparar un numero que el usuario ingrese, y mostraremos 3 frases dependiendo de los siguientes casos:
Si el número es mas grande, Si es mas pequeño o si es igual.
Entonces tenemos que usar: ">", "<" y "=".
Ahora tenemos el siguiente código

Program HelloWorld(output);
uses crt;
var MiNumero, TuNumero : integer;
begin
 MiNumero := 20;
 clrscr;
 writeln('Escribe un numero');
 readln(TuNumero);
 if TuNumero < MiNumero then
  writeln('Mi numero es mas grande');
 if TuNumero > MiNumero then
  writeln('Tu numero es mas grande');
 if TuNumero = MiNumero then
  writeln('Los numeros son iguales');
 readln;
end.

Como verás, primero creamos dos variables del tipo "integer", luego le preguntamos al usuario por un número que vamos a almacenar en la variable "TuNumero", luego vienen las comparaciones. La primera vamos a comprobar si el numero que el usuario escribió es mas pequeño que el que nosotros le asignamos a la variable "MiNumnero", si es así, le mostraremos un mensaje que dice: "Mi número es mas grande". Para el segundo caso, vamos a comprobar si le número que escribió es más grande y para el tercer caso solo comprobaremos si el número es igual.

El código de arriba tambien se puede plantear de la siguiente manera
Program HelloWorld(output);
uses crt;
var MiNumero, TuNumero : integer;
begin
 MiNumero := 20;
 clrscr;
 writeln('Escribe un numero');
 readln(TuNumero);
 if TuNumero < MiNumero then
  writeln('Mi numero es mas grande')
 else if TuNumero > MiNumero then
  writeln('Tu numero es mas grande')
 else if TuNumero = MiNumero then
  writeln('Los numeros son iguales');
 readln;
end.

Para hacerlo de la forma anterior hacemos uso de la palabra reservada "else", seguida de la palabra reservada "if" y después la condición (cómo en el primer caso). Ademas, no hacemos uso de ";" porque cuando lo hacemos, indicamos que es el final de la instrucción "if", entonces solo hay que ponerlo para indicar que terminamos.

Else

Para hacer uso de la palabra else, debemos de seguir los mismo pasos que para "else if", ademas debemos de usarlo siempre al final de la instruccion if.
Ahora supongamos que solo queremos saber si el numero es igual o diferente al que nosotros almacenamos en nuestra variable, podemos hacer lo mismo que al inicio o podemos hacer uso de "else" (un tanto inpractico pero sirve para demostrar lo que queremos).
Entonces podemos usar código como el que sigue:

Program HelloWorld(output);
uses crt;
var MiNumero, TuNumero : integer;
begin
 MiNumero := 20;
 clrscr;
 writeln('Escribe un numero');
 readln(TuNumero);
 if TuNumero = MiNumero then
  writeln('Los numeros son iguales')
 else
  writeln('Los numeros son diferentes');
 readln;
end.

A veces resulta realmente dificil poder listar todas las posibles situaciones, pero con el uso de "else" nos podemos ahorrar un poco.
Y bien, por ahora es todo, en el sigueinte post continuaremos con mas de programacion en pascal.

Los leo luego.

Learning Machine #4 - Programando en Pascal - Declaraciones, ámbitos y constantes.

Hola a todos, el día de hoy vamos a continuar con la programación es Pascal. En el post anterior, vimos cuales son los tipos de datos que se pueden usar, pero olvide algo realmente fundamental, el cómo declararlas.



Para declarar una variable en Pascal, es necesario usar la palabra reservada "var", la mayorías de las variables globales que van a ser usadas por el programa, deben de ser declaradas justo antes del inicio del programa, siempre es bueno declarar la mayor parte de estas en este punto, así el programa al iniciar, cargará la mayor parte de los recursos necesarios al inicio.
En pascal la forma de declarar las variables es la siguiente:
NombreDeLaVariable : tipo;
El nombre de la variable debe de empezar por una letra y puede incluir números y símbolos que no sean usados por el lenguaje de ":" y finalmente el tipo del cual será.
Por ejemplo, vamos a crear 5 variables:

var
Valor1 : integer;
Valor2 : integer;
Valor3 : integer;
Nombre1 : string;
Nombre2 : string;
begin
...

Con el fragmento de código anterior, hemos creado 3 variables del tipo integer llamadas: "Valor1", "Valor2" y "Valor3", además de 2 variables del tipo string llamadas: "Nombre1" y "Nombre2".
Se puede ahorrar un poco de espacio si en lugar de crear una variable del mismo tipo por linea, se declaran todas las variables similares en una sola. Para hacer eso, hay que escribir el nombre de la variable seguido de una coma ",", cuando se hallan declarado todas la variables que queramos que pertenezcan al mismo tipo, se pondrá ":" seguido por el tipo al cual pertenecerán. Entonces, el fragmento de código anterior puede crearse de la siguiente manera:


var
Valor1, Valor2, Valor3 : integer;
Nombre1, Nombre2 : string;
begin
...


Constantes.

Las constantes son valores que se declaran y se les asigna un valor al mismo tiempo, una vez que el valor a sido establecido, ya no es posible cambiarlo. Cuando queremos hacer uso del la constante, basta con mandarla a llamar por su nombre y entonces se usará el valor que está posea.
Si se intenta cambiar el valor de una constante en algún punto del programa, este producirá un error en tiempo de compilación.
Los siguientes son ejemplos de declaración de variables:
Const
e = 2.7182818;
MyName = 'XWork';
El uso de constantes es realmente útil cuando trabajemos con valores conocidos que no se van a modificar.

Visibilidad de los datos.

Algo muy importante que hay que tomar en cuenta, es la visibilidad de los datos, cuando creamos las variables en esta parte del programa, al estar en la parte principal, estos serán visibles para todo el programa, es decir estos valores podrán ser leídos y escritos desde cualquier lugar de la aplicación. Lo importante de esto, es que hay que tener muy en mente que es lo que vamos a hacer y cómo vamos a hacerlo, supongamos que creamos variables al inicio del programa y llegamos al punto en que el programa es tan grande y tiene tantas variables que por error escribimos el nombre de una variable que no es la que estamos usando. Al haber modificado los datos de una variable sin darnos cuenta, el programa producirá un error en algún momento. Aunque en pascal solo hay ámbitos, local y global. Cuando una variable se crea dentro de una función o procedimiento (cosas que veremos un poco después), esta solo sera visible dentro de la funcion (o procedimiento) en el cual se haya creado.
En lenguajes que sean orientados a objetos (c#, delphi, etc), existen palabras reservadas que sirven para indicar directamente si una variable es privada o no, es decir si se puede usar más allá del ámbito en el cual fue creada.

Y bien, por ahora es todo, en el siguiente post continuaremos con más programación para Pascal

Los leo luego