Conversión de decimal con parte fraccionaria en C

C – Convertir decimal con parte fraccionaria

En este post de programación en ANSI C te mostraré 3 conversiones entre bases numéricas: de decimal a binario, a octal y a hexadecimal. La diferencia con mis otros posts es que en este caso vamos a convertir también la parte fraccionaria, decimal o como le llames a lo que va después del punto decimal.

Entonces vamos a convertir entre binario y decimal con punto decimal, además de convertir a octal, hexadecimal y a todas las otras bases.

Así que al final, con el código que te mostraré, podrás convertir números en base 10 con parte fraccionaria a cualquier base. Por ejemplo, convertir 3722.24 base 10 a E8A.3D70 base 16.

Te repito que la principal diferencia es que ahora este conversor en C soporta conversiones con punto decimal, cosa que me habían solicitado varios usuarios en mis otros posts.

Explicación del algoritmo

Para entender cómo funciona este algoritmo debemos entender la forma manual de hacer la conversión. Para este ejemplo convertiré el número a hexadecimal (pero esto que te muestro igual funciona con base 2 y base 8), así que tenemos 3722.24 como entrada.

Presta atención en que la base es 16, y los dígitos de la misma son 0123456789ABCDEF.

Lo primero que hacemos es separar la parte entera y la parte fraccionaria, para ello podemos usar modf. Ahora trabajamos con las partes por separado.

Parte entera

En el caso de la parte entera vamos dividiendo entre 16 y obteniendo el residuo de la división. Cada valor de residuo irá conformando la cadena hexadecimal. El proceso va así:

3722 % 16 = 10. Se concatena AL INICIO el dígito A. Ahora la parte entera es 232
232 % 16 = 8. Se concatena AL INICIO el dígito 8. Ahora la parte entera es 14
14 % 16 = 14. Se concatena AL INICIO el dígito E. Ahora la parte entera es 0

Y hasta este momento tenemos la parte entera ya en hexadecimal que equivale a E8A. Fíjate en que el proceso se detiene cuando la parte entera es 0.

Parte fraccionaria

En este caso vamos a multiplicar la parte fraccionaria por 16 y tomar el valor entero del resultado para agregarlo al final de la cadena hexadecimal.

Ahora la parte fraccionaria igualmente se toma del resultado anterior, y se repite el proceso hasta que el sobrante sea 0. El proceso es así:

0.240000 * 16 = 3.840000. Sobran 3.000000. El dígito es 3. Ahora la parte fraccionaria es 0.840000
0.840000 * 16 = 13.440000. Sobran 13.000000. El dígito es D. Ahora la parte fraccionaria es 0.440000
0.440000 * 16 = 7.040000. Sobran 7.000000. El dígito es 7. Ahora la parte fraccionaria es 0.040000
0.040000 * 16 = 0.640000. Sobran 0.000000. El dígito es 0. Ahora la parte fraccionaria es 0.640000

Y la parte fraccionaria como hexadecimal es 3D70. Por lo que el número completo ya convertido es: E8A.3D70.

Esto mismo que aplicamos aquí se va a aplicar para la conversión de decimal a octal y decimal a binario con parte fraccionaria, solo vamos a cambiar la base y los dígitos que la conforman.

Función general para la conversión

Anteriormente había creado una función para cada conversión, pero me di cuenta de que se puede crear una función que proporciona un método de conversión desde decimal a cualquier otra base.

Sin más preámbulo, te la muestro. En los comentarios se explica el funcionamiento:

/**
 * Convierte un número decimal a cualquier base
 * @param numeroDecimal El número en base 10
 * @param cadenaResultado Cadena en donde se almacenará el resultado, pues esta función no devuelve nada, solo coloca el resultado en la cadena indicada
 * @param base La base a la que se desea convertir el número. Por ejemplo, para convertir a hexadecimal, la base es 16
 * @param digitos Los dígitos que conforman la base a la que se convierte el número. Por ejemplo, para la base 16 son 0123456798ABCDEF
 * @author Parzibyte https://parzibyte.me/blog
 */
void decimalACualquierBase(double numeroDecimal, char cadenaResultado[MAXIMA_LONGITUD_CADENA], const int base, const char digitos[])
{
    /*
     * Separar fracción y entero
     * */
    double parteEnteraDouble; // Temporal para modf
    double parteFraccionaria;
    parteFraccionaria = modf(numeroDecimal, &parteEnteraDouble);
    int parteEntera = (int)parteEnteraDouble;
    /*
     * Declarar cadenas
     * */
    char cadenaParteEntera[MAXIMA_LONGITUD_CADENA] = "";
    char cadenaParteFraccionaria[MAXIMA_LONGITUD_CADENA] = "";
    // Realizar la conversión de la parte entera
    while (parteEntera > 0)
    {
        int residuo = parteEntera % base;
        char digito = digitos[residuo];
        concatenarCharACadena(digito, cadenaParteEntera);
        parteEntera /= base;
    }
    // Invertimos la cadena
    invertirCadena(cadenaParteEntera);
    // Realizar conversión de la parte fraccionaria
    double sobrante;
    do
    {
        double resultado = parteFraccionaria * base;
        parteFraccionaria = modf(resultado, &sobrante);
        char digito = digitos[(int)sobrante];
        concatenarCharACadena(digito, cadenaParteFraccionaria);
    } while (sobrante != 0);
    // Concatenar finalmente la parte entera y fraccionaria en el resultado
    strcpy(cadenaResultado, ""); // Limpiar cadena
    strcat(cadenaResultado, cadenaParteEntera);
    strcat(cadenaResultado, ".");
    strcat(cadenaResultado, cadenaParteFraccionaria);
}

Los métodos que no son para el cálculo son para trabajar con cadenas o para invertirlas.

En este caso esta función soporta conversión de números con fracción desde la base 10 a binario, octal y hexadecimal. No devuelve nada, pues coloca el resultado en la cadena que se proporciona al llamarla. Ahora es momento de ver su modo de uso.

Antes que nada debemos declarar el número que se va a convertir y la cadena en donde se almacenará el resultado de la conversión:

// En dónde almacenar el resultado, debe ser una cadena
char resultado[MAXIMA_LONGITUD_CADENA] = "";
// Solicitar número al usuario;
double decimal;
printf("Ingresa el decimal:\n");
scanf("%lf", &decimal);

Obviamente el número puede venir de cualquier lugar o puedes declararlo tú mismo.

Decimal a hexadecimal

Comenzando con el caso del ejemplo, para hacer la conversión invocamos a la función que la base es 16 con los dígitos adecuados:

// Decimal a hexadecimal
decimalACualquierBase(decimal, resultado, 16, "0123456789ABCDEF");
printf("Resultado de convertir el decimal %lf a hexadecimal: %s\n", decimal, resultado);

Decimal a octal

Lo mismo que anteriormente, solo que ahora los dígitos van del 0 al 7 y la base es 8:

// Decimal a octal
decimalACualquierBase(decimal, resultado, 8, "01234567");
printf("Resultado de convertir el decimal %lf a octal: %s\n", decimal, resultado)

Decimal a binario

Para terminar el ejemplo, también podemos convertir de decimal a binario:

// Decimal a binario
decimalACualquierBase(decimal, resultado, 2, "01");
printf("Resultado de convertir el decimal %lf a binario: %s\n", decimal, resultado);

De hecho con esta función podemos convertir a cualquier otra base siempre y cuando indiquemos los dígitos.

Poniendo todo junto

Conversión de decimal con parte fraccionaria en C
Conversión de decimal con parte fraccionaria en C

Es momento de ver el código en lenguaje C completo, así como el método main. Todo queda así:

/*
    https://parzibyte.me/blog
*/
#include <stdio.h>
#include <string.h>
#include <math.h>

#define MAXIMA_LONGITUD_CADENA 100

void invertirCadena(char cadena[])
{
    int longitud = strlen(cadena);
    int i;
    for (i = 0; i < strlen(cadena) / 2; i++)
    {
        char temporal = cadena[i];
        cadena[i] = cadena[longitud - i - 1];
        cadena[longitud - i - 1] = temporal;
    }
}

void concatenarCharACadena(char c, char *cadena)
{
    char cadenaTemporal[2];
    cadenaTemporal[0] = c;
    cadenaTemporal[1] = '\0';
    strcat(cadena, cadenaTemporal);
}

/**
 * Convierte un número decimal a cualquier base
 * @param numeroDecimal El número en base 10
 * @param cadenaResultado Cadena en donde se almacenará el resultado, pues esta función no devuelve nada, solo coloca el resultado en la cadena indicada
 * @param base La base a la que se desea convertir el número. Por ejemplo, para convertir a hexadecimal, la base es 16
 * @param digitos Los dígitos que conforman la base a la que se convierte el número. Por ejemplo, para la base 16 son 0123456798ABCDEF
 * @author Parzibyte https://parzibyte.me/blog
 */
void decimalACualquierBase(double numeroDecimal, char cadenaResultado[MAXIMA_LONGITUD_CADENA], const int base, const char digitos[])
{
    /*
     * Separar fracción y entero
     * */
    double parteEnteraDouble; // Temporal para modf
    double parteFraccionaria;
    parteFraccionaria = modf(numeroDecimal, &parteEnteraDouble);
    int parteEntera = (int)parteEnteraDouble;
    /*
     * Declarar cadenas
     * */
    char cadenaParteEntera[MAXIMA_LONGITUD_CADENA] = "";
    char cadenaParteFraccionaria[MAXIMA_LONGITUD_CADENA] = "";
    // Realizar la conversión de la parte entera
    while (parteEntera > 0)
    {
        int residuo = parteEntera % base;
        char digito = digitos[residuo];
        concatenarCharACadena(digito, cadenaParteEntera);
        parteEntera /= base;
    }
    // Invertimos la cadena
    invertirCadena(cadenaParteEntera);
    // Realizar conversión de la parte fraccionaria
    double sobrante;
    do
    {
        double resultado = parteFraccionaria * base;
        parteFraccionaria = modf(resultado, &sobrante);
        char digito = digitos[(int)sobrante];
        concatenarCharACadena(digito, cadenaParteFraccionaria);
    } while (sobrante != 0);
    // Concatenar finalmente la parte entera y fraccionaria en el resultado
    strcpy(cadenaResultado, ""); // Limpiar cadena
    strcat(cadenaResultado, cadenaParteEntera);
    strcat(cadenaResultado, ".");
    strcat(cadenaResultado, cadenaParteFraccionaria);
}

int main(int argc, char const *argv[])
{
    // En dónde almacenar el resultado, debe ser una cadena
    char resultado[MAXIMA_LONGITUD_CADENA] = "";
    // Solicitar número al usuario;
    double decimal;
    printf("Ingresa el decimal:\n");
    scanf("%lf", &decimal);
    // Decimal a hexadecimal
    decimalACualquierBase(decimal, resultado, 16, "0123456789ABCDEF");
    printf("Resultado de convertir el decimal %lf a hexadecimal: %s\n", decimal, resultado);
    // Decimal a octal
    decimalACualquierBase(decimal, resultado, 8, "01234567");
    printf("Resultado de convertir el decimal %lf a octal: %s\n", decimal, resultado);
    // Decimal a binario
    decimalACualquierBase(decimal, resultado, 2, "01");
    printf("Resultado de convertir el decimal %lf a binario: %s\n", decimal, resultado);
    return 0;
}

Nota: he probado con otras calculadoras y en ocasiones el método presentado aquí no es tan preciso para la parte fraccionaria. Esto es porque me basé en el método manual para la conversión. Recuerda que igualmente eres libre de mejorar el código.

Te dejo más entradas sobre C en mi blog.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *