Contenido:
Imagen: http://pikabu.ru/
Introducción
En los primeros días de aprendizaje de Java, me encontré con un tipo de primitivas tan curioso como los números de coma flotante. Inmediatamente me interesé por sus características y, más aún, por la forma en que estaban escritos en código binario (que está interconectado). A diferencia de cualquier rango de números enteros, incluso en un rango muy pequeño (por ejemplo, de 1 a 2) hay un número infinito de ellos. Y al tener un tamaño de memoria finito, es imposible expresar este conjunto. Entonces, ¿cómo se expresan en binario y cómo funcionan? Lamentablemente, las explicaciones en
la wiki y un artículo bastante interesante sobre Habré
aquí no me dieron una comprensión completa, aunque sentaron las bases. Me di cuenta sólo después de leer este
artículo de análisis a la mañana siguiente de leerlo.
Excursión a la historia.
(
tomado de este artículo sobre Habré ) En los años 60 y 70, cuando las computadoras eran grandes y los programas pequeños, todavía no existía un estándar único para los cálculos, así como un estándar para expresar el número de punto flotante en sí. Cada computadora lo hacía de manera diferente y cada una tenía sus propios errores. Pero a mediados de los años 70, Intel decidió fabricar nuevos procesadores con aritmética "mejorada" compatible y al mismo tiempo estandarizarla. Los profesores William Kahan y John Palmer (no, no son autores de libros sobre cerveza) fueron contratados para desarrollarlo. Hubo algo de drama, pero se desarrolló un nuevo estándar. Ahora este estándar se llama IEEE754.
Formato de número de punto flotante
Incluso en los libros de texto escolares, todo el mundo se enfrentaba a una forma inusual de escribir números muy grandes o muy pequeños de la forma
1,2 × 10 3 o
1,2 E3 , que es igual a
1,2 × 1000 = 1200 . Esto se llama método de notación exponencial. En este caso, estamos ante la expresión de un número usando la fórmula:
N=M×n p , donde
- N = 1200 - el número resultante
- M = 1,2 - mantisa - parte fraccionaria, sin tener en cuenta órdenes
- n = 10 es la base de orden. En este caso y cuando no hablamos de ordenadores, la base es el número 10
- p = 3 - grado de base
Muy a menudo se supone que la base del orden es 10
y sólo se escribe la mantisa y el valor de la base, separándolos con la letra
E. En nuestro ejemplo, di las entradas equivalentes
1.2 × 10 3 y
1.2 E3 . Si todo está claro y hemos terminado la excursión nostálgica al plan de estudios de la escuela, ahora recomiendo olvidar esto, porque al formar un número de coma flotante estamos ante potencias de dos, no de decenas, es decir
n = 2 , toda la fórmula armoniosa
1.2E3 se rompe y realmente me rompió el cerebro.
Signo y grado
¿Entonces que tenemos? Como resultado, también tenemos un número binario, que consta de
una mantisa , la parte que elevaremos a una potencia y la potencia misma. Además, al igual que ocurre con los tipos enteros, los números de punto flotante tienen un bit que determina el signo: si el número será positivo o negativo. Como ejemplo, propongo considerar el tipo
float
, que consta de 32 bits. Con números de doble precisión
double
la lógica es la misma, sólo que hay el doble de bits. De los 32 bits, el primero más significativo se asigna al signo, los siguientes 8 bits se asignan al exponente, la potencia a la que elevaremos la mantisa, y los 23 bits restantes, a la mantisa. Para demostrarlo, veamos un ejemplo:
el primer bit es muy simple. Si el valor del primer bit
es 0 , entonces el número que obtendremos será
positivo . Si el bit es
1 , entonces el número será
negativo . El siguiente bloque de 8 bits es un bloque exponente. El exponente se escribe como un número normal
de ocho bits y, para obtener el grado requerido, al número resultante debemos restar
127. En nuestro caso, los ocho bits del exponente son
10000001 . Esto corresponde al número
129 . Si tiene alguna pregunta sobre cómo calcular esto, la imagen muestra una respuesta rápida. Se puede obtener una versión ampliada en cualquier curso de álgebra booleana.
1×2 7 + 0×2 6 + 0×2 5 + 0×2 4 + 0×2 3 + 0×2 2 + 0×2 1 + 1×2 0 = 1×128 + 1×1 = 128+ 1=129 No es difícil calcular que el número máximo que podemos obtener de estos 8 bits es
11111111 2 = 255 10 (el subíndice
2 y
10 significan sistemas numéricos binario y decimal) Sin embargo, si usamos sólo valores de exponente positivo (
de 0 a 255 ), entonces los números resultantes tendrán muchos números antes del punto decimal, pero no después. Para obtener valores negativos del grado, es necesario restar
127 al exponente generado . Así, el rango de grados será
de -127 a 128 . Usando nuestro ejemplo, el grado requerido será
129-127 = 2 . Recordemos este número por ahora.
mantisa
Ahora sobre la mantisa. Consta de 23 bits, pero al principio siempre implica otra unidad para la que no están asignados los bits. Esto se hace por razones de conveniencia y economía. El mismo número se puede expresar en diferentes potencias sumando ceros a la mantisa antes o después del punto decimal. La forma más sencilla de entender esto es con un exponente decimal:
120.000 = 1,2×10 5 = 0,12×10 6 = 0,012×10 7 = 0,0012×10 8 etc. Sin embargo, al ingresar un número fijo en la cabeza de la mantisa, recibiremos números nuevos cada vez. Demos por sentado que antes de nuestros 23 bits habrá uno más con uno. Normalmente este bit está separado del resto por un punto, que, sin embargo, no significa nada. Simplemente es más conveniente 1. 111000000000000000000000
Ahora la mantisa resultante debe elevarse a una potencia de izquierda a derecha, disminuyendo la potencia en uno con cada paso. Comenzamos con el valor de la potencia que obtuvimos como resultado del cálculo, es decir,
2 (elegí deliberadamente un ejemplo simple para no escribir cada valor de la potencia de dos y no los calculé en la tabla de arriba cuando el el bit correspondiente es cero)
1×2 2 + 1×2 1 + 1×2 0 + 1×2 -1 = 1×4 + 1×2 + 1×1 + 1×0,5 = 4+2+1+0,5 = 7.5 y obtuve el resultado
7.5 , la corrección se puede verificar, por ejemplo, en
este enlace
Resultados
Un número de punto flotante estándar
float
consta de 32 bits, el primer bit es el signo (+ o -), los ocho siguientes son el exponente y los 23 siguientes son la mantisa. Por signo, si el bit 0 es un número positivo. Si el bit 1 es negativo.
Por exponencial : convertimos bit a bit a un número decimal (el primer bit de la izquierda es
128 , el segundo es
64 , el tercero es
32 , el cuarto es
16 , el quinto es
8 , el sexto es
4 , el séptimo es
2 , el octavo es
1 ), al número resultante restamos
127 , obtenemos el grado con el que comenzaremos.
Según la mantisa , a los 23 bits existentes al frente agregamos otro bit con el valor 1 y desde allí comenzamos a elevarlo a la potencia que recibimos, disminuyendo esta potencia con cada bit posterior.
¡Eso es todo amigos, niños! PD: Como tarea, utilizando este artículo, deja en los comentarios tus versiones de por qué ocurren errores de precisión con una gran cantidad de operaciones aritméticas con números de coma flotante.
GO TO FULL VERSION