Tutoriales Aitorrio
Tutoriales Aitorrio 



Donativo para el sitio de elGuille

Buscar en Google y en elGuille.info:
Búsqueda personalizada

Ir a la sección de Visual Studio 2005 Utilidades .NET 2.0

Conversor de números a distintas bases numéricas

 
Publicado el 31/Oct/2007
Actualizado el 31/Oct/2007
Autor: Guillermo 'guille' Som

En esta utilidad encontrarás una clase con dos funciones, una para convertir un valor decimal en cualquier base numérica, y al revés, de cualquier base numérica a decimal. El problemas es que en .NET no soporta todos los valores que se pueden indicar si la base que estás usando es en base 36, pero bueno, ya te pondré un código para que eso sea posible. Y como de costumbre, con código para VB como para C#.



 

Introducción:

Pues eso... lo dicho, creo que ya poco más puedo contar que no haya contado ahí arriba... pero bueno, para que no sea eso solo no vayas a pensar que he puesto la explicación donde la he puesto para que hagas otra cosa, je je.

La clase que te muestro (Conversor) define varios métodos, una serie de ellos te sirven para convertir un número decimal (base 10) en otro número de otra base distinta, por ejemplo, base 2 (binario), base 8 (octal), base 16 (hexadecimal) o cualquier otra base desde 2 a 36.

Además, hay otra serie de funciones que sirven para lo contrario, es decir, para convertir números de cualquier base numérica (de 2 a 36) a un número decimal (base 10).

El problema de las bases grandes, por ejemplo 36, es que .NET no tiene capacidad para almacenar un valor de ese tipo, al menos no para almacenarlo sin que sea de forma exponencial, así que... como verás en el siguiente ejemplo, pues no se comporta como debiera.

De otras bases a decimal
========================
101011011 en base 2 -> 347
10765478 en base 8 -> 294247
FF00125E0 en base 16 -> 68451116512
GUILLEMOLA en base 36 -> 1711050165663742
ELGUILLEMOLA en base 36 -> 1921194231198726144
 

De decimal a otras bases
========================
101011011 en base 2 -> 347
1076547 en base 8 -> 294247
FF00125E0 en base 16 -> 68451116512
GUILLEMOLA en base 36 -> 1711050165663742
ELGUILLEMOR0 en base 36 -> 1921194231198726144

Si te fijas en la última línea de cada bloque, al usar la base 36 con el "número" ELGUILLEMOLA, (recuerda que una base 36 te permitirá usar números cuyas cifras serán del 0 al 9 y de la A a la Z), da como resultado 1921194231198726144, que no es totalmente correcto, ya que el valor debería ser 1921194231198726142 (a lo mejor es que mi código está mal, pero creo que es problema de los redondeos, la cosa es que quiero que veas lo que ocurre al convertir el número nuevamente a la base 36... je, je, seguramente es que mi ordenador sabe que soy medio moro, je, je... en fin...

Y no es un truco para hacer un chiste ni nada de eso, si ejecutas el código que te muestro más abajo, verás que es ese el resultado que muestra.

Nota:
En realidad, el código lo he depurado y mejorado y el que te muestro ahora hace los cálculos (en realidad los redondeos) mejor, y ya no se equivoca con el valor ese de ELGUILLEMOLA, pero en el código de Visual Basic te dejo comentadas las líneas del código anterior que si que me convertía en moro, je, je.

Por cierto, en el código de C# no está solucionado ese problemilla de redondeos, pero no creo que te resulte difícil solucionarlo, sobre todo si te fijas en el de VB y ves los cambios que he hecho.

Es que como se supone que los programadores de Visual Basic somos más torpes, pues hay que darle más ayuda que a los de C# ;-)))

 

Pero esto tiene solución, aunque para ello hay que usar otros tipos de datos. En mi caso, como hace un rato anuncié, estoy finalizando la librería para trabajar con tipos numéricos de gran precisión (librería de la que puedes ver el código completo y te la puedes bajar desde mi nuevo sitio Programar por programar), aunque todavía no está publicado el código que hace esto de las conversiones, pero para que veas el resultado "real" de esas conversiones de ahí arriba:

De otras bases a decimal
========================
101011011 en base 2 -> 347
10765478 en base 8 -> 294247
FF00125E0 en base 16 -> 68451116512
GUILLEMOLA en base 36 -> 1711050165663742
ELGUILLEMOLA en base 36 -> 1921194231198726142

 
De decimal a otras bases
========================
101011011 en base 2 -> 347
1076547 en base 8 -> 294247
FF00125E0 en base 16 -> 68451116512
GUILLEMOLA en base 36 -> 1711050165663742
ELGUILLEMOLA en base 36 -> 1921194231198726142

En este segundo ejemplo, el tipo de datos que estoy usando es BigInt, mientras que en el anterior es UInt64 (ulong).

 

Espero que te sea de utilidad.

Nos vemos.
Guillermo

Abajo tienes el código completo de la clase, tanto para Visual Basic como para C#, y más abajo todavía, tienes el link para bajar los proyectos para Visual Basic 2005 y Visual C# 2005.

Decirte que no lo he probado en otras versiones anteriores, pero debería funcionar, al menos el código de C#, ya que en las versiones anteriores de Visual Basic no disponíamos del tipo ULong, pero de querer convertirlo, puedes cambiarlo por Decimal y casi seguro que te funciona, pero no lo he probado, así que... solo garantizo que funciona en las versiones 2005 o superiores.

El programa de ejemplo que usa la clase Conversor:

Para Visual Basic 2005:

Dim nums() As String = {"101011011", "10765478", "FF00125E0", _
                        "GUILLEMOLA", "ELGUILLEMOLA"}

Dim bases() As Integer = {2, 8, 16, 36, 36}
Dim n(0 To bases.Length - 1) As ULong


Console.WriteLine("De otras bases a decimal")
Console.WriteLine("========================")
For i As Integer = 0 To bases.Length - 1
    n(i) = Conversor.FromNumBase(nums(i), bases(i))
    Console.WriteLine("{0,16} en base {1,2} -> {2}", nums(i), bases(i), n(i))
Next
Console.WriteLine()

Console.WriteLine("De decimal a otras bases")
Console.WriteLine("========================")
For i As Integer = 0 To bases.Length - 1
    nums(i) = Conversor.ToNumBase(n(i).ToString, bases(i))
    Console.WriteLine("{0,16} en base {1,2} -> {2}", nums(i), bases(i), n(i))
Next
Console.WriteLine()

 

 

Para Visual C# 2005:

string[] nums = { "101011011", "10765478", "FF00125E0", 
                    "GUILLEMOLA", "ELGUILLEMOLA" };

int[] bases = { 2, 8, 16, 36, 36 };
ulong[] n = new ulong[(bases.Length)];


Console.WriteLine("De otras bases a decimal");
Console.WriteLine("========================");
for(int i = 0; i < bases.Length; i++)
{
    n[i] = Conversor.FromNumBase(nums[i], bases[i]);
    Console.WriteLine("{0,16} en base {1,2} -> {2}", 
                        nums[i], bases[i], n[i]);
}
Console.WriteLine();

Console.WriteLine("De decimal a otras bases");
Console.WriteLine("========================");
for(int i = 0; i < bases.Length; i++)
{
    nums[i] = Conversor.ToNumBase(n[i].ToString(), bases[i]);
    Console.WriteLine("{0,16} en base {1,2} -> {2}", 
                        nums[i], bases[i], n[i]);
}
Console.WriteLine();

 

 


Código para Visual Basic.NET (VB.NET) El código para Visual Basic 2005 o superior
'------------------------------------------------------------------------------
' Clase Conversor                                                   (31/Oct/07)
' Para convertir valores decimales a cualquier otra base numérica
'
' ©Guillermo 'guille' Som, 2007
'------------------------------------------------------------------------------
Option Strict On

Imports Microsoft.VisualBasic
Imports System

Imports System.Collections.Generic
Imports System.Text
'Imports System.Diagnostics

Namespace elGuille.Developer


    ''' <summary>
    ''' Clase para convertir bases numéricas
    ''' </summary>
    ''' <remarks></remarks>
    Public Class Conversor

        ' 
        ' Funciones de conversión a otras bases
        '


        ''' <summary>
        ''' Convierte un número decimal en una base distinta
        ''' Las bases permitadas son de 2 a 36
        ''' </summary>
        ''' <param name="num"></param>
        ''' <param name="nBase">
        ''' Base a la que se convertirá (de 2 a 36)
        ''' (con los tipos de .NET ñla base 36 no es fiable)
        ''' </param>
        ''' <param name="conSeparador">
        ''' Si se añade un separador cada 4 cifras
        ''' </param>
        ''' <param name="trimStart">
        ''' Si se quitan los ceros a la izquierda
        ''' </param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function ToNumBase(ByVal num As String, _
                                         ByVal nBase As Integer, _
                                         ByVal conSeparador As Boolean, _
                                         ByVal trimStart As Boolean) As String
            Dim s As New StringBuilder
            Dim n As ULong = CULng(num)
            If n = 0 AndAlso conSeparador = False AndAlso trimStart = False Then
                Return "0"
            End If

            ' La base debe ser como máximo 36
            ' (por las letras del alfabeto (26) + 10 dígitos)
            ' F = 70 - 55 + 1 = 16
            ' Z = 90 - 55 + 1 = 36
            If nBase < 2 OrElse nBase > 36 Then
                Throw New ArgumentOutOfRangeException( _
                            "La base debe ser como máximo 36 y como mínimo 2")
            End If

            Dim j As Integer = 0
            'Dim nu As Double = n
            Dim nu As Decimal = n

            While nu > 0
                'Dim k As Double = (nu / nBase)
                Dim k As Decimal = CDec(nu) / CDec(nBase)
                nu = Fix(k)
                Dim f As Integer = CInt((k - nu) * nBase)

                Select Case f
                    Case Is > 9 ' letras
                        s.Append(ChrW(f + 55))
                    Case Else ' números
                        s.Append(ChrW(f + 48))
                End Select
                If conSeparador Then
                    j = j + 1
                    If j = 4 Then
                        j = 0
                        s.Append(" ")
                    End If
                End If
            End While

            ' Hay que darle la vuelta a la cadena
            Dim ac() As Char = s.ToString.ToCharArray
            Array.Reverse(ac)
            s = New StringBuilder(ac)


            If trimStart Then
                Return s.ToString.TrimStart(" 0".ToCharArray).TrimEnd
            Else
                Return s.ToString.TrimEnd
            End If
        End Function


        ''' <summary>
        ''' Convierte de cualquier base a Double
        ''' </summary>
        ''' <param name="num">
        ''' El número en formato de la base
        ''' </param>
        ''' <param name="base">
        ''' La base del número a convertir
        ''' </param>
        ''' <returns></returns>
        ''' <remarks>
        ''' </remarks>
        Public Shared Function FromNumBase(ByVal num As String, _
                                           ByVal base As Integer) As ULong
            Const aMay As Integer = AscW("A") - 10
            Const aMin As Integer = AscW("a") - 10
            Dim i As Integer = 0
            Dim n As ULong = 0

            num = num.TrimStart("0".ToCharArray)

            For j As Integer = num.Length - 1 To 0 Step -1
                Select Case num(j).ToString
                    Case "0"
                        i += 1
                    Case " "
                        ' nada
                    Case "1" To "9"
                        Dim k As Integer = CInt(num(j).ToString)
                        If k - base >= 0 Then Continue For
                        'n = CULng(n + k * System.Math.Pow(base, i))
                        n = n + CULng(k * System.Math.Pow(base, i))
                        i += 1
                    Case "A" To "Z"
                        Dim k As Integer = AscW(num(j)) - aMay
                        If k - base >= 0 Then Continue For
                        'n = CULng(n + k * System.Math.Pow(base, i))
                        n = n + CULng(k * System.Math.Pow(base, i))
                        i += 1
                    Case "a" To "z"
                        Dim k As Integer = AscW(num(j)) - aMin
                        If k - base >= 0 Then Continue For
                        'n = CULng(n + k * System.Math.Pow(base, i))
                        n = n + CULng(k * System.Math.Pow(base, i))
                        i += 1
                End Select
            Next

            Return n
        End Function


        '
        ' Sobrecargas
        '

        ''' <summary>
        ''' Convierte un número decimal en una base distinta
        ''' Las bases permitadas son de 2 a 36
        ''' No se muestran los ceros a la izquierda y
        ''' no se separan los dígitos en grupos de 4
        ''' </summary>
        ''' <param name="num"></param>
        ''' <param name="nBase"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function ToNumBase(ByVal num As String, _
                                         ByVal nBase As Integer) As String
            Return ToNumBase(num, nBase, False, True)
        End Function

        ''' <summary>
        ''' Convierte un número decimal en una base distinta
        ''' Las bases permitadas son de 2 a 36
        ''' no se separan los dígitos en grupos de 4
        ''' </summary>
        ''' <param name="num"></param>
        ''' <param name="nBase"></param>
        ''' <param name="trimStart"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function ToNumBase(ByVal num As String, _
                                         ByVal nBase As Integer, _
                                         ByVal trimStart As Boolean) As String
            Return ToNumBase(num, nBase, False, trimStart)
        End Function

        '
        ' Funciones específicas
        '

        ''' <summary>
        ''' Convierte de Decimal a binario (base 2)
        ''' </summary>
        ''' <param name="num">
        ''' El número a convertir en binario
        ''' se convierte internamente a ULong como máximo
        ''' </param>
        ''' <param name="conSeparador"></param>
        ''' <param name="trimStart"></param>
        ''' <returns></returns>
        ''' <remarks>
        ''' </remarks>
        Public Shared Function DecToBin(ByVal num As String, _
                                        Optional ByVal conSeparador As Boolean = True, _
                                        Optional ByVal trimStart As Boolean = True) As String
            Return ToNumBase(num, 2, conSeparador, trimStart)
        End Function

        ''' <summary>
        ''' Convierte de Decimal a hexadecimal (base 16)
        ''' </summary>
        ''' <param name="num">
        ''' El número a convertir en hexadecimal
        ''' se convierte internamente a ULong como máximo
        ''' </param>
        ''' <param name="conSeparador"></param>
        ''' <param name="trimStart"></param>
        ''' <returns></returns>
        ''' <remarks>
        ''' </remarks>
        Public Shared Function DecToHex(ByVal num As String, _
                                        Optional ByVal conSeparador As Boolean = True, _
                                        Optional ByVal trimStart As Boolean = True) As String
            Return ToNumBase(num, 16, conSeparador, trimStart)
        End Function

        ''' <summary>
        ''' Convierte de Decimal a octal (base 8)
        ''' </summary>
        ''' <param name="num">
        ''' El número a convertir en binario
        ''' se convierte internamente a ULong como máximo
        ''' </param>
        ''' <param name="conSeparador"></param>
        ''' <param name="trimStart"></param>
        ''' <returns></returns>
        ''' <remarks>
        ''' </remarks>
        Public Shared Function DecToOctal(ByVal num As String, _
                                        Optional ByVal conSeparador As Boolean = True, _
                                        Optional ByVal trimStart As Boolean = True) As String
            Return ToNumBase(num, 8, conSeparador, trimStart)
        End Function


        ''' <summary>
        ''' Convierte de Hexadecimal a Double
        ''' </summary>
        ''' <param name="num"></param>
        ''' <returns></returns>
        ''' <remarks>
        ''' </remarks>
        Public Shared Function FromHex(ByVal num As String) As Double
            Return FromNumBase(num, 16)
        End Function

        ''' <summary>
        ''' Convierte de Octal a Double
        ''' </summary>
        ''' <param name="num"></param>
        ''' <returns></returns>
        ''' <remarks>
        ''' </remarks>
        Public Shared Function FromOct(ByVal num As String) As Double
            Return FromNumBase(num, 8)
        End Function


        ''' <summary>
        ''' Convierte de Binario a Double
        ''' </summary>
        ''' <param name="num"></param>
        ''' <returns></returns>
        ''' <remarks>
        ''' </remarks>
        Public Shared Function FromBin(ByVal num As String) As Double
            Return FromNumBase(num, 2)
        End Function


    End Class

End Namespace

 

Código para C Sharp (C#) El código para C# (cualquier versión)
//-----------------------------------------------------------------------------
// Clase Conversor                                                  (31/Oct/07)
// Para convertir valores decimales a cualquier otra base numérica
//
// ©Guillermo 'guille' Som, 2007
//-----------------------------------------------------------------------------
using System;

using System.Collections.Generic;
using System.Text;

namespace elGuille.Developer
{


    /// <summary>
    /// Clase para convertir bases numéricas
    /// </summary>
    /// <remarks></remarks>
    public class Conversor
    {

        //
        // Funciones de conversión a otras bases
        //


        /// <summary>
        /// Convierte un número decimal en una base distinta
        /// Las bases permitadas son de 2 a 36
        /// </summary>
        /// <param name="num"></param>
        /// <param name="nBase">
        /// Base a la que se convertirá (de 2 a 36)
        /// (con los tipos de .NET ñla base 36 no es fiable)
        /// </param>
        /// <param name="conSeparador">
        /// Si se añade un separador cada 4 cifras
        /// </param>
        /// <param name="trimStart">
        /// Si se quitan los ceros a la izquierda
        /// </param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static string ToNumBase(string num, 
                                       int nBase, 
                                       bool conSeparador, 
                                       bool trimStart)
        {
            StringBuilder s = new StringBuilder();
            ulong n = Convert.ToUInt64(num);
            if(n == 0 && conSeparador == false && trimStart == false)
            {
                return "0";
            }

            // La base debe ser como máximo 36
            // (por las letras del alfabeto (26) + 10 dígitos)
            // F = 70 - 55 + 1 = 16
            // Z = 90 - 55 + 1 = 36
            if(nBase < 2 || nBase > 36)
            {
                throw new ArgumentOutOfRangeException(
                    "La base debe ser como máximo 36 y como mínimo 2");
            }

            int j = 0;
            double nu = n;

            while(nu > 0)
            {
                double k = (nu / nBase);
                nu = System.Math.Floor(k);
                int f = Convert.ToInt32((k - nu) * nBase);

                if(f > 9)// letras
                {
                    s.Append((char)(f + 55));
                }
                else // números
                {
                    s.Append((char)(f + 48));
                }
                if(conSeparador)
                {
                    j = j + 1;
                    if(j == 4)
                    {
                        j = 0;
                        s.Append(" ");
                    }
                }
            }

            // Hay que darle la vuelta a la cadena
            char[] ac = s.ToString().ToCharArray();
            Array.Reverse(ac);
            s = new StringBuilder();
            foreach(char c in ac)
                s.Append(c);


            if(trimStart)
            {
                return s.ToString().TrimStart(" 0".ToCharArray()).TrimEnd();
            }
            else
            {
                return s.ToString().TrimEnd();
            }
        }

        //
        // Sobrecargas
        //

        /// <summary>
        /// Convierte un número decimal en una base distinta
        /// Las bases permitadas son de 2 a 36
        /// No se muestran los ceros a la izquierda y
        /// no se separan los dígitos en grupos de 4
        /// </summary>
        /// <param name="num"></param>
        /// <param name="nBase"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static string ToNumBase(string num, int nBase)
        {
            return ToNumBase(num, nBase, false, true);
        }

        /// <summary>
        /// Convierte un número decimal en una base distinta
        /// Las bases permitadas son de 2 a 36
        /// no se separan los dígitos en grupos de 4
        /// </summary>
        /// <param name="num"></param>
        /// <param name="nBase"></param>
        /// <param name="trimStart"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static string ToNumBase(string num, int nBase, bool trimStart)
        {
            return ToNumBase(num, nBase, false, trimStart);
        }

        //
        // Funciones específicas
        //

        /// <summary>
        /// Convierte de Decimal a binario (base 2)
        /// </summary>
        /// <param name="num">
        /// El número a convertir en binario
        /// se convierte internamente a ULong como máximo
        /// </param>
        /// <param name="conSeparador"></param>
        /// <param name="trimStart"></param>
        /// <returns></returns>
        /// <remarks>
        /// v.0.11 29/Oct/07
        /// </remarks>
        public static string DecToBin(string num, bool conSeparador, bool trimStart)
        {
            return ToNumBase(num, 2, conSeparador, trimStart);
        }

        /// <summary>
        /// Convierte de Decimal a hexadecimal (base 16)
        /// </summary>
        /// <param name="num">
        /// El número a convertir en hexadecimal
        /// se convierte internamente a ULong como máximo
        /// </param>
        /// <param name="conSeparador"></param>
        /// <param name="trimStart"></param>
        /// <returns></returns>
        /// <remarks>
        /// </remarks>
        public static string DecToHex(string num, bool conSeparador, bool trimStart)
        {
            return ToNumBase(num, 16, conSeparador, trimStart);
        }

        /// <summary>
        /// Convierte de Decimal a octal (base 8)
        /// </summary>
        /// <param name="num">
        /// El número a convertir en binario
        /// se convierte internamente a ULong como máximo
        /// </param>
        /// <param name="conSeparador"></param>
        /// <param name="trimStart"></param>
        /// <returns></returns>
        /// <remarks>
        /// </remarks>
        public static string DecToOctal(string num, bool conSeparador, bool trimStart)
        {
            return ToNumBase(num, 8, conSeparador, trimStart);
        }



        /// <summary>
        /// Convierte de cualquier base a Double
        /// </summary>
        /// <param name="num">
        /// El número en formato de la base
        /// </param>
        /// <param name="base">
        /// La base del número a convertir
        /// </param>
        /// <returns></returns>
        /// <remarks>
        /// </remarks>
        public static ulong FromNumBase(string num, int nbase)
        {
            const int aMay = 'A' - 10;
            const int aMin = 'a' - 10;
            int i = 0;
            ulong n = 0;

            num = num.TrimStart("0".ToCharArray());

            for(int j = num.Length - 1; j >= 0; j--)
            {
                if(num[j] == '0')
                {
                    i += 1;
                }
                else if(num[j] == ' ')
                {
                    // nada
                }
                else if(num[j] >= '1' && num[j] <= '9')
                {
                    int k = num[j] - 48;
                    if(k - nbase >= 0)
                        continue;
                    n = (ulong)(n + k * System.Math.Pow(nbase, i));
                    i += 1;
                }
                else if(num[j] >= 'A' && num[j] <= 'Z')
                {
                    int k = num[j] - aMay;
                    if(k - nbase >= 0)
                        continue;
                    n = (ulong)(n + k * System.Math.Pow(nbase, i));
                    i += 1;
                }
                else if(num[j] >= 'a' && num[j] <= 'z')
                {
                    int k = num[j] - aMin;
                    if(k - nbase >= 0)
                        continue;
                    n = (ulong)(n + k * System.Math.Pow(nbase, i));
                    i += 1;
                }
            }

            return n;
        }


        /// <summary>
        /// Convierte de Hexadecimal a Double
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        /// <remarks>
        /// </remarks>
        public static double FromHex(string num)
        {
            return FromNumBase(num, 16);
        }

        /// <summary>
        /// Convierte de Octal a Double
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        /// <remarks>
        /// </remarks>
        public static double FromOct(string num)
        {
            return FromNumBase(num, 8);
        }


        /// <summary>
        /// Convierte de Binario a Double
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        /// <remarks>
        /// </remarks>
        public static double FromBin(string num)
        {
            return FromNumBase(num, 2);
        }
    }
}

Espacios de nombres usados en el código de este artículo:

System.Text
 


Código de ejemplo (comprimido):

Fichero con el código de ejemplo: Conversor_bases_numericas.zip - 15.50 KB

Contiene los dos proyectos (VB y C#), sin binarios, sólo el código.

(MD5 checksum: 9EBEF10CCB890BD6CA3711B9FA2A9373)


 


Cosas que te pueden interesar



Mentor de
SolidQ
Most Valuable Professional
MVP de .NET (antes Visual Basic)
de octubre de 1997 a septiembre de 2015



Orador internacional de Ineta
Orador de Ineta Latam

ir al índice del Guille


Escribir un mensaje al Guille (mensaje EN elGuille.info)
Has entrado usando el host: elguille.info
Puedes verlo también en: http://mundoprogramacion.com/net/vs2005/utilidades/conversor_bases_numericas.aspx