Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


9.4.1  Representación interna

  Numeros en coma flotante:

El programa es una versión simplificada del Conversor automático de formatos ( 2.2.4a) incluido al tratar de la representación interna de cantidades numéricas de coma flotante. Esta versión solo muestra la representación de números en simple precisión (32 bits), aunque puede ser fácilmente adaptado para representar números de doble precisión (64 bits).

Como entrada puede introducirse un número cualquiera, incluso en notación científica. Como salida se muestra el formato de almacenamiento interno según el estándar IEEE 754 para números de simple precisión. Primero el bit de signo; a continuación el exponente, y finalmente la mantisa.  Naturalmente es necesario que el equipo utilice realmente este formato para su almacenamiento interno (lo que es prácticamente seguro en la informática actual).

#include <iostream>        // Representación IEEE 754
#include <conio.h>
#include <values.h>
using namespace std;

void map(float);           // mostrar patron de bits del número introducido

int main() {               // ====================
    double uDouble = 0;
    while (true) {         // bucle principal
        cout << "\r\nIntroduzca un numero (0 para terminar)"; 
        cout << "\r\npuede usar notacion cientifica. xEy :" << endl; 
        cin >> uDouble;
        if (uDouble == 0) break;
        cout << "\r\nValor seleccionado: " << uDouble << endl;
        double aDouble;
        if (uDouble < 0) aDouble = -uDouble;
        else aDouble = uDouble;
        if (aDouble > MAXFLOAT) {
            cout << "\r\nValor fuera de rango para float (32 bits)";
            cout << "\r\nvalor maximo " << MAXFLOAT << endl;
        }
        if (aDouble < MINFLOAT) {
            cout << "\r\nValor fuera de rango para float (32 bits)";
            cout << "\r\nvalor minimo " << MINFLOAT << endl;
        }
        map((float) uDouble);    // invocar la subrutina de salida
    }
    return EXIT_SUCCESS;
}

void map (float val) {          // Mostrar patron de bits
    cout << "\r\n\n\ Signo Exp. Mantisa\r\n";
    cout << "Rep. IEEE754: ";
    float* pflo = &val;
    char* pchar = reinterpret_cast<char*> (pflo);

    // suponemos corriendo el programa en un sistema Little-endian (p.e. Windows) 
    unsigned char value = *(pchar+3);     // empezamos por el byte de la derecha

 

    for(int i = 7; i >= 0; i--) {
        cout << ((value & (1 << i)) ? "1" : "0");
        if (i == 7) cout << " ";         // separador entre bit de signo y exponente
    }

    value = *(pchar+2);
    for( i = 7; i >= 0; i--) {
        cout << ((value & (1 << i)) ? "1" : "0");
        if (i == 7) cout << " ";         // separar bits de exponente y mantisa
    }

    value = *(pchar+1);
    for( i = 7; i >= 0; i--) cout << ((value & (1 << i)) ? "1" : "0");

    value = *pchar;
    for( i = 7; i >= 0; i--) cout << ((value & (1 << i)) ? "1" : "0");


    cout << "\r\n";
}

Resultados obtenidos con diversas entradas:

Introduzca un numero (0 para terminar)
puede usar notacion cientifica. xxEy :
4.363435e-35
Valor seleccionado: 4.36344e-35

          Signo   Exp.   Mantisa
Rep. IEEE754: 0 00001100 11010000000000000000000


-23040
Valor seleccionado: -23040

          Signo   Exp.   Mantisa
Rep. IEEE754: 1 10001101 01101000000000000000000


4.77544580e-39
Valor seleccionado: 4.77545e-39

Valor fuera de rango para float (32 bits)
valor minimo 1.17549e-38

          Signo   Exp.   Mantisa
Rep. IEEE754: 0 00000000 01101000000000000000000

 Comentario:

El cuerpo de la función main se limita a aceptar una entrada y enviar el número a la rutina de presentación. Si los valores están fuera del rango permitido para un float (32 bits), se muestra un mensaje de aviso, aunque continúa el proceso. El código está optimizado para el compilador Borland C++ Builder.  En caso de utilizarse otro, por ejemplo, GNU Cpp para Windows (versión Mingw), es posible que se presenten errores con las constantes manifiestas MINFLOAT y MAXFLOAT.  En cuyo caso pueden suprimirse las sentencias de comprobación o colocar los valores adecuados.

La función map que muestra el patrón de bits, supone que utilizamos una máquina "Little-endian" ( 2.2.6a), como es el caso de sistemas Windows sobre plataformas Intel. En estos casos, los 4 octetos del número están almacenados en orden inverso. Suponiendo un orden creciente de posiciones de memoria, el que consideramos bit más significativo, es el último. Por ejemplo, la posición real de los octetos del primer ejemplo es el siguiente:

00000000 00000000 01101000 00000110


El valor 0/1 de cada bit individual se muestra mediante una expresión que utiliza el AND entre bits (bitand):

cout << ((value & (1 << i)) ? "1" : "0");         // L.0

Como las operaciones de manejo de bits exigen operandos de tipo entero ( 4.9.3), se recurre a un pequeño truco, ya que no es posible utilizar directamente el float val que contiene el número cuya radiografía interna estamos realizando:

    float* pflo = &val;                             // L.1
    char* pchar = reinterpret_cast<char*> (pflo);   // L.2
 
    unsigned char value = *(pchar+3);               // L:3

En primer lugar se construye un puntero pflo que contiene la dirección de inicio de val (L.1). A continuación creamos un puntero-a-char, pchar, que señala al mismo sitio (L.2). Para esto utilizamos un modelado por la fuerza bruta ( 4.9.9d). Finalmente creamos un char value (de 8 bits), por el procedimiento de suponer que empieza en la dirección del puntero pchar (L.3).  Observe que aquí jugamos con el desplazamiento +3, +2, etc. respecto de la posición inicial, para seleccionar el octeto correspondiente de val. que queremos analizar en cada bucle.

Observe que el compilador realiza automáticamente una última conversión; es la necesaria para transformar el char value a un tipo entero (int) tal como se necesita en la operación AND de la sentencias L.0.