En la mayoría de los lenguajes de programación, los números de coma flotante se representan de manera muy similar a la notación científica : con un exponente y una mantisa (también llamada significado). Un número muy simple, por ejemplo 9.2
, es en realidad esta fracción:
5179139571476070 * 2 -49
Donde está el exponente -49
y está la mantisa 5179139571476070
. La razón por la que es imposible representar algunos números decimales de esta manera es que tanto el exponente como la mantisa deben ser enteros. En otras palabras, todos los flotadores deben ser un número entero multiplicado por una potencia entera de 2 .
9.2
puede ser simple 92/10
, pero 10 no puede expresarse como 2 n si n está limitado a valores enteros.
Ver los datos
Primero, algunas funciones para ver los componentes que hacen un 32 y 64 bits float
. Pase por alto estos si solo le importa la salida (ejemplo en Python):
def float_to_bin_parts(number, bits=64):
if bits == 32: # single precision
int_pack = 'I'
float_pack = 'f'
exponent_bits = 8
mantissa_bits = 23
exponent_bias = 127
elif bits == 64: # double precision. all python floats are this
int_pack = 'Q'
float_pack = 'd'
exponent_bits = 11
mantissa_bits = 52
exponent_bias = 1023
else:
raise ValueError, 'bits argument must be 32 or 64'
bin_iter = iter(bin(struct.unpack(int_pack, struct.pack(float_pack, number))[0])[2:].rjust(bits, '0'))
return [''.join(islice(bin_iter, x)) for x in (1, exponent_bits, mantissa_bits)]
Hay una gran cantidad de complejidad detrás de esa función, y sería bastante tangente explicarlo, pero si le interesa, el recurso importante para nuestros propósitos es el módulo de estructura .
Python float
es un número de doble precisión de 64 bits. En otros lenguajes como C, C ++, Java y C #, la precisión doble tiene un tipo separado double
, que a menudo se implementa como 64 bits.
Cuando llamamos a esa función con nuestro ejemplo 9.2
, esto es lo que obtenemos:
>>> float_to_bin_parts(9.2)
['0', '10000000010', '0010011001100110011001100110011001100110011001100110']
Interpretando los datos
Verá que he dividido el valor de retorno en tres componentes. Estos componentes son:
- Firmar
- Exponente
- Mantissa (también llamada Significand, o Fraction)
Firmar
El signo se almacena en el primer componente como un solo bit. Es fácil de explicar: 0
significa que el flotador es un número positivo; 1
significa que es negativo Porque 9.2
es positivo, nuestro valor de signo es 0
.
Exponente
El exponente se almacena en el componente medio como 11 bits. En nuestro caso 0b10000000010
,. En decimal, eso representa el valor 1026
. Una peculiaridad de este componente es que debe restar un número igual a 2 (# de bits) - 1 - 1 para obtener el verdadero exponente; en nuestro caso, eso significa restar 0b1111111111
(número decimal 1023
) para obtener el verdadero exponente 0b00000000011
(número decimal 3).
Mantissa
La mantisa se almacena en el tercer componente como 52 bits. Sin embargo, también hay una peculiaridad en este componente. Para comprender esta peculiaridad, considere un número en notación científica, como este:
6.0221413x10 23
La mantisa sería la 6.0221413
. Recuerde que la mantisa en notación científica siempre comienza con un solo dígito distinto de cero. Lo mismo es cierto para el binario, excepto que el binario solo tiene dos dígitos: 0
y 1
. ¡Entonces la mantisa binaria siempre comienza con 1
! Cuando se almacena un flotador, 1
se omite el frente de la mantisa binaria para ahorrar espacio; tenemos que volver a colocarlo al frente de nuestro tercer elemento para obtener la verdadera mantisa:
1.0010011001100110011001100110011001100110011001100110
Esto implica algo más que una simple adición, porque los bits almacenados en nuestro tercer componente en realidad representan la parte fraccional de la mantisa, a la derecha del punto de raíz .
Cuando tratamos con números decimales, "movemos el punto decimal" multiplicando o dividiendo por potencias de 10. En binario, podemos hacer lo mismo multiplicando o dividiendo por potencias de 2. Dado que nuestro tercer elemento tiene 52 bits, dividimos por 2 52 para moverlo 52 lugares a la derecha:
0.0010011001100110011001100110011001100110011001100110
En notación decimal, eso es lo mismo que dividir 675539944105574
entre 4503599627370496
para obtener 0.1499999999999999
. (Este es un ejemplo de una relación que se puede expresar exactamente en binario, pero solo aproximadamente en decimal; para más detalles, consulte: 675539944105574/4503599627370496 ).
Ahora que hemos transformado el tercer componente en un número fraccionario, la suma 1
da la verdadera mantisa.
Recapitulando los componentes
- Signo (primer componente):
0
para positivo, 1
para negativo
- Exponente (componente medio): resta 2 (# de bits) - 1 - 1 para obtener el verdadero exponente
- Mantissa (último componente): divide entre 2 (# de bits) y suma
1
para obtener la verdadera mantisa
Calcular el número
Al unir las tres partes, se nos da este número binario:
1.0010011001100110011001100110011001100110011001100110 x 10 11
Que luego podemos convertir de binario a decimal:
1.1499999999999999 x 2 3 (¡inexacto!)
Y multiplique para revelar la representación final del número con el que comenzamos ( 9.2
) después de ser almacenado como un valor de coma flotante:
9.1999999999999993
Representando como una fracción
9.2
Ahora que hemos construido el número, es posible reconstruirlo en una fracción simple:
1.0010011001100110011001100110011001100110011001100110 x 10 11
Cambia la mantisa a un número entero:
10010011001100110011001100110011001100110011001100110 x 10 11-110100
Convierte a decimal:
5179139571476070 x 2 3-52
Resta el exponente:
5179139571476070 x 2 -49
Convierta el exponente negativo en división:
5179139571476070/2 49
Multiplicar exponente:
5179139571476070/562949953421312
Que es igual a:
9.1999999999999993
9.5
>>> float_to_bin_parts(9.5)
['0', '10000000010', '0011000000000000000000000000000000000000000000000000']
Ya puedes ver que la mantisa tiene solo 4 dígitos seguidos de muchos ceros. Pero vamos a través de los pasos.
Montar la notación científica binaria:
1.0011 x 10 11
Desplaza el punto decimal:
10011 x 10 11-100
Resta el exponente:
10011 x 10 -1
Binario a decimal:
19 x 2 -1
Exponente negativo a la división:
19/2 1
Multiplicar exponente:
19/2
Igual a:
9.5
Otras lecturas