Vamos a programar #35 - DecToAny.

Hola de nuevo a todos, el día de hoy vamos a ver código en C# que se encargará de convertir de un número decimal a cualquier base (en realidad hasta base 20). Al igual que en las ocasiones anteriores, gran parte del código, será una adaptación de lo que hemos hecho en post anteriores.

Haciendo un poco de memoria.

Para empezar recordemos que las conversión de un número decimal a un número en otra base, se realiza mediante divisiones sucesivas de el numero resultante de la división anterior entre la base. Si tenemos el numero X decimal y lo queremos pasar a la base B, debemos de dividir X/B y al resultado R, en la siguiente división lo dividiremos entre la base (B), este proceso se repite mientras que el resultado R sea mayor que la base.

Portando el código a c#.

Sabiendo lo anterior, podemos crear una funcion cómo la que sigue:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DecToAny
{
 public partial class FrmMain : Form
 {
  private List<TextBox> TextBoxes = new List<TextBox>();
  private List<int> DecToAny(int Number, int Base)
  {
   int LastNumber = Number;
   int Garbage;
   List<int> result = new List<int>();
   if (LastNumber < Base)
   {
    result.Add(LastNumber);
   }
   else
   {
   while (LastNumber >= Base) {
    Garbage = LastNumber % Base;
    LastNumber = LastNumber / Base;
    if (LastNumber < Base)
    {
     result.Add(Garbage);
     result.Add(LastNumber);
    }
    else
    {
     result.Add(Garbage);
    }
   }
   }

   return result;
  }
  private string ListToString(List<int> Lista)
  {
   string Out = "";
   Lista.Reverse();
   foreach (int Numero in Lista) {
    if (Numero < 10)
    {
     Out += Numero.ToString();
    }
    else
    {
     Out += NumberToLetra(Numero);
    }
   }
   return Out;
  }
  public FrmMain()
  {
   InitializeComponent();
  }
  private char NumberToLetra(int Number)
  {
   return (char)(Number + 55);
  }
  private void FrmMain_Load(object sender, EventArgs e)
  {
   TextBoxes.Add(txtBase2);
   TextBoxes.Add(txtBase3);
   TextBoxes.Add(txtBase4);
   TextBoxes.Add(txtBase5);
   TextBoxes.Add(txtBase6);
   TextBoxes.Add(txtBase7);
   TextBoxes.Add(txtBase8);
   TextBoxes.Add(txtBase9);
   TextBoxes.Add(txtBase10);
   TextBoxes.Add(txtBase11);
   TextBoxes.Add(txtBase12);
   TextBoxes.Add(txtBase13);
   TextBoxes.Add(txtBase14);
   TextBoxes.Add(txtBase15);
   TextBoxes.Add(txtBase16);
   TextBoxes.Add(txtBase17);
   TextBoxes.Add(txtBase18);
   TextBoxes.Add(txtBase19);
   TextBoxes.Add(txtBase20);

  }

  private void BtnConvert_Click(object sender, EventArgs e)
  {
   for (int T = 0; T < TextBoxes.Count; T++)
   {
    TextBoxes[T].Text = ListToString(DecToAny(int.Parse(TxtNIn.Text), (T + 2)));
   }
  }
 }
}
El código anterior consta de 3 funciones. La función que hace gran parte del trabajo es "DecToAny", en ella se crean dos variables. La variable "LastNumber" será la encargada de almacenar el resultado de las divisiones anteriores. La variable "Garbage" será utilizada para guardar los "residuos" de las divisiones, estos son usados para formar el número final. Antes de siquiera empezar con el ciclo while, se hace una comprobación; si el número es menor que la base, simplemente se regresa una lista del tipo "int" con un solo elemento, en este caso, el mismo numero que se ingreso cómo parámetro para "Number". Si por el contrario el numero es igual o mayor que la base; se entra en el bucle while y  se comienzan a hacer las divisiones. En el bucle, se comprueba que el resultado de la división que esta almacenado en "LastNumber" sea mayor que la base. Cuando la base es mayor que el resultado de la división, el residuo de esta se agrega a la lista "result", pero cuando la condición ya no se cumple, entonces agrega a la misma lista el valor residual de la división y además el resultado de la misma. Finalmente devuelve una lista del tipo "int" con todos los valores.
La funcion "ListToString" se usa para convertir la lista del tipo "int" en un string (valga la redundancia). Para empezar, primero se invierte el orden en el cual están los elementos, hay que recordar que el resultado de las divisiones se usa en orden inverso en donde el primer digito, sera el residuo de la ultima division seguido del resultado entero de la misma seguido de los residuos del resto de las otras divisiones. Para devolver el resultado final, tambien se hace uso interno de la funcion "NumberToLetra", hay que recordar que para el decimo digito se usa la letra A.
Una vez que se ejecuta la función "DecToAny" hay que pasársela cómo parámetro a la función "ListToString" y el resultado será un string con una cadena equivalente al numero en la base especificada.

A tomar en cuenta.

Algo muy importante a tomar en cuenta es que las letras que se usan representan los valores más allá del decimo digito. Para el decimo digito usamos la A y asi sucesivamente hasta la Z (incluso más) La siguiente tabla muestra los valores disponibles.
ABCDEFGHIJKLMNOPQRSTUVWXYZ
1011121314151617181920212223242526272829303132333435
Entonces la base más grande que podemos usar es 35, pero eso solo para mantener humanamente legible cualquier número,pero podríamos seguir con el siguiente carácter ascii (que es el que usamos) y así el número Z0 sera algo totalmente diferente a z0.

Cómo de costumbre el código fuente completo lo puedes descargar de mi dropbox.
Por ahora es todo, los leo luego

2 comentarios