Bienvenido a nuestra página web, en este sitio vas a encontrar la resolución a lo que buscas.
Solución:
Primero, un artículo que debería considerar leer, si quiere comprender mejor las debilidades del punto flotante: “Lo que todo científico informático debe saber sobre la aritmética del punto flotante”, http://www.validlab.com/goldberg/paper.pdf
Y ahora un poco de carne.
El siguiente código es básico e intenta producir un flotador de precisión simple IEEE-754 a partir de un unsigned int
en el rango 0
Los flotantes de precisión simple IEEE-754 se dividen en tres campos: un bit de signo único, 8 bits de exponente y 23 bits de significando (a veces llamado mantisa). IEEE-754 usa un oculto 1 significand, lo que significa que el significand es en realidad un total de 24 bits. Los bits se empaquetan de izquierda a derecha, con el bit de signo en el bit 31, el exponente en los bits 30 .. 23 y el significado en los bits 22 .. 0. El siguiente diagrama de Wikipedia ilustra:
El exponente tiene un sesgo de 127, lo que significa que el exponente real asociado con el número de coma flotante es 127 menos que el valor almacenado en el campo del exponente. Por tanto, un exponente de 0 se codificaría como 127.
(Nota: Puede que le interese el artículo completo de Wikipedia. Ref: http://en.wikipedia.org/wiki/Single_precision_floating-point_format)
Por lo tanto, el número IEEE-754 0x40000000 se interpreta de la siguiente manera:
- Bit 31 = 0: valor positivo
- Bits 30 .. 23 = 0x80: Exponent = 128-127 = 1 (también conocido como 21)
- Los bits 22 .. 0 son todos 0: Significand = 1.00000000_00000000_0000000. (Tenga en cuenta que restauré el 1 oculto).
Entonces el valor es 1.0 x 21 = 2,0.
Para convertir un unsigned int
en el rango limitado dado anteriormente, entonces, a algo en formato IEEE-754, puede usar una función como la que se muestra a continuación. Toma los siguientes pasos:
- Alinea el 1 inicial del entero con la posición del oculto 1 en la representación de coma flotante.
- Al alinear el entero, registra el número total de cambios realizados.
- Enmascara lo oculto 1.
- Usando el número de cambios realizados, calcula el exponente y lo agrega al número.
- Utilizando
reinterpret_cast
, convierte el patrón de bits resultante en unfloat
. Esta parte es un truco feo, porque usa un puntero con tipo de juego. También puede hacer esto abusando de ununion
. Algunas plataformas proporcionan una operación intrínseca (como_itof
) para hacer esta reinterpretación menos fea.
Hay formas mucho más rápidas de hacer esto; este está destinado a ser pedagógicamente útil, si no súper eficiente:
float uint_to_float(unsigned int significand)
(significand & 0x7FFFFF);
// Reinterpret as a float and return. This is an evil hack.
return *reinterpret_cast< float* >( &merged );
Puede hacer que este proceso sea más eficiente utilizando funciones que detectan el 1 inicial en un número. (Estos a veces tienen nombres como clz
para “contar ceros a la izquierda”, o norm
para “normalizar”.)
También puede extender esto a números con signo registrando el signo, tomando el valor absoluto del entero, realizando los pasos anteriores y luego colocando el signo en el bit 31 del número.
Para enteros> = 224, el entero entero no encaja en el campo significativo del formato flotante de 32 bits. Esta es la razón por la que necesita “redondear”: pierde LSB para que el valor se ajuste. Por lo tanto, varios enteros terminarán mapeando al mismo patrón de punto flotante. El mapeo exacto depende del modo de redondeo (redondear hacia -Inf, redondear hacia + Inf, redondear hacia cero, redondear hacia el par más cercano). Pero el quid de la cuestión es que no puede introducir 24 bits en menos de 24 bits sin alguna pérdida.
Puede ver esto en términos del código anterior. Funciona alineando el 1 principal con la posición 1 oculta. Si un valor era> = 224, el código debería cambiar Derecha, no izquierda, y eso necesariamente aleja a los LSB. Los modos de redondeo solo le dicen cómo manejar los bits desplazados.
¿Ha verificado la representación de punto flotante IEEE 754?
En forma normalizada de 32 bits, tiene el bit de signo (mantisa), exponente de 8 bits (exceso-127, creo) y mantisa de 23 bits en “decimal” excepto que el “0”. se elimina (siempre en esa forma) y la base es 2, no 10. Es decir: el valor de MSB es 1/2, el siguiente bit 1/4 y así sucesivamente.
La respuesta de Joe Z es elegante, pero el rango de valores de entrada es muy limitado. El flotador de 32 bits puede almacenar todos los valores enteros del siguiente rango:
[-224…+224] = [-16777216…+16777216]
y algunos otros valores fuera de este rango.
Todo el rango estaría cubierto por esto:
float int2float(int value)
// handles all values from [-2^24...2^24]
// outside this range only some integers may be represented exactly
// this method will use truncation 'rounding mode' during conversion
// we can safely reinterpret it as 0.0
if (value == 0) return 0.0;
if (value == (1U<<31)) // ie -2^31
// -(-2^31) = -2^31 so we'll not be able to handle it below - use const
// value = 0xCF000000;
return (float)INT_MIN; // *((float*)&value); is undefined behaviour
int sign = 0;
// handle negative values
if (value < 0)
sign = 1U << 31;
value = -value;
// although right shift of signed is undefined - all compilers (that I know) do
// arithmetic shift (copies sign into MSB) is what I prefer here
// hence using unsigned abs_value_copy for shift
unsigned int abs_value_copy = value;
// find leading one
int bit_num = 31;
int shift_count = 0;
for(; bit_num > 0; bit_num--)
if (abs_value_copy & (1U<= 23)
// need to shift right
shift_count = bit_num - 23;
abs_value_copy >>= shift_count;
else
// need to shift left
shift_count = 23 - bit_num;
abs_value_copy <<= shift_count;
break;
// exponent is biased by 127
int exp = bit_num + 127;
// clear leading 1 (bit #23) (it will implicitly be there but not stored)
int coeff = abs_value_copy & ~(1<<23);
// move exp to the right place
exp <<= 23;
union
int rint;
float rfloat;
ret = coeff ;
return ret.rfloat;
Por supuesto, hay otros medios para encontrar el valor abs de int (sin ramas). De manera similar, el couting de ceros a la izquierda también se puede hacer sin una rama, así que trate este ejemplo como ejemplo ;-).
Te mostramos reseñas y puntuaciones
Tienes la opción de asentar nuestro ensayo dejando un comentario o dejando una valoración te estamos eternamente agradecidos.