El formato de punto flotante de doble precisión (a veces llamado FP64 o float64 ) es un formato de número de punto flotante , que generalmente ocupa 64 bits en la memoria de la computadora; representa una amplia gama de valores numéricos mediante el uso de un punto de base flotante .
Se puede elegir la precisión doble cuando el rango o la precisión de la precisión simple serían insuficientes.
En el estándar IEEE 754 , el formato base 2 de 64 bits se conoce oficialmente como binary64 ; se lo llamó double en IEEE 754-1985 . IEEE 754 especifica formatos de punto flotante adicionales, incluida la precisión simple base 2 de 32 bits y, más recientemente, representaciones de base 10 ( punto flotante decimal ).
Uno de los primeros lenguajes de programación que proporcionó tipos de datos de punto flotante fue Fortran . [ cita requerida ] Antes de la adopción generalizada de IEEE 754-1985, la representación y las propiedades de los tipos de datos de punto flotante dependían del fabricante y el modelo de la computadora, y de las decisiones tomadas por los implementadores del lenguaje de programación. Por ejemplo, el tipo de datos de doble precisión de GW-BASIC era el formato de punto flotante MBF de 64 bits .
Formatos de punto flotante |
---|
IEEE 754 |
|
Other |
Alternatives |
El formato binario de punto flotante de precisión doble es un formato que se utiliza con frecuencia en las PC, debido a su mayor rango que el de punto flotante de precisión simple, a pesar de su rendimiento y costo de ancho de banda. Se lo conoce comúnmente simplemente como double . El estándar IEEE 754 especifica que un binary64 tiene:
El bit de signo determina el signo del número (incluso cuando este número es cero, que tiene signo ).
El campo de exponente es un entero sin signo de 11 bits de 0 a 2047, en forma sesgada : un valor de exponente de 1023 representa el cero real. Los exponentes varían de −1022 a +1023 porque los exponentes de −1023 (todos 0) y +1024 (todos 1) están reservados para números especiales.
La precisión de mantis de 53 bits proporciona una precisión de entre 15 y 17 dígitos decimales significativos (2 −53 ≈ 1,11 × 10 −16 ). Si una cadena decimal con un máximo de 15 dígitos significativos se convierte al formato de doble precisión IEEE 754, lo que da como resultado un número normal, y luego se convierte nuevamente a una cadena decimal con el mismo número de dígitos, el resultado final debe coincidir con la cadena original. Si un número de doble precisión IEEE 754 se convierte a una cadena decimal con al menos 17 dígitos significativos y luego se convierte nuevamente a una representación de doble precisión, el resultado final debe coincidir con el número original. [1]
El formato se escribe con la mantisa que tiene un bit entero implícito de valor 1 (excepto para datos especiales, consulte la codificación de exponentes a continuación). Con los 52 bits de la mantisa de fracción (F) que aparecen en el formato de memoria, la precisión total es, por lo tanto, de 53 bits (aproximadamente 16 dígitos decimales, 53 log 10 (2) ≈ 15,955). Los bits se distribuyen de la siguiente manera:
El valor real asumido por un dato de doble precisión de 64 bits con un exponente sesgado dado y una fracción de 52 bits es
o
Entre 2 52 = 4.503.599.627.370.496 y 2 53 = 9.007.199.254.740.992 los números representables son exactamente los enteros. Para el siguiente rango, de 2 53 a 2 54 , todo se multiplica por 2, por lo que los números representables son los pares, etc. Por el contrario, para el rango anterior de 2 51 a 2 52 , el espaciado es 0,5, etc.
El espaciado como fracción de los números en el rango de 2 n a 2 n +1 es 2 n −52 . Por lo tanto, el error de redondeo relativo máximo al redondear un número al número representable más cercano (la épsilon de máquina ) es 2 −53 .
El ancho de 11 bits del exponente permite la representación de números entre 10 −308 y 10 308 , con una precisión total de 15 a 17 dígitos decimales. Al comprometer la precisión, la representación subnormal permite valores aún más pequeños, hasta aproximadamente 5 × 10 −324 .
El exponente binario de punto flotante de doble precisión se codifica utilizando una representación binaria de desplazamiento , donde el desplazamiento cero es 1023; también conocido como sesgo de exponente en el estándar IEEE 754. Algunos ejemplos de tales representaciones serían:
y = = =1:000000000012 00116 | (exponente más pequeño para números normales ) | ||
y = = =1023:011111111112 3ff16 | (desplazamiento cero) | ||
y = = =1029:100000001012 40516 | |||
y = = =2046:111111111102 7fe16 | (máximo exponente) |
Los exponentes y tienen un significado especial:00016
7ff16
000000000002
= se utiliza para representar un cero con signo (si F = 0) y números subnormales (si F ≠ 0); y00016
111111111112
= se utiliza para representar ∞ (si F = 0) y NaNs (si F ≠ 0),7ff16
donde F es la parte fraccionaria del significado . Todos los patrones de bits son codificaciones válidas.
Salvo las excepciones anteriores, el número completo de doble precisión se describe mediante:
En el caso de números subnormales ( e = 0) el número de doble precisión se describe mediante:
0 01111111111 000000000000000000000000000000000000000000000000000000 2 ≙ 3FF0 0000 0000 0000 16 ≙ +2 0 × 1 = 1 |
0 01111111111 0000000000000000000000000000000000000000000000000000001 2 ≙ 3FF0 0000 0000 0001 16 ≙ +2 0 × (1 + 2 −52 ) ≈ 1.000000000000002, el número más pequeño > 1 |
0 01111111111 000000000000000000000000000000000000000000000000000010 2 ≙ 3FF0 0000 0000 0002 16 ≙ +2 0 × (1 + 2 −51 ) ≈ 1,000000000000004 |
0 10000000000 0000000000000000000000000000000000000000000000000000 2 ≙ 4000 0000 0000 0000 16 ≙ +2 1 × 1 = 2 |
1 10000000000 00000000000000000000000000000000000000000000000000000 2 ≙ C000 0000 0000 0000 16 ≙ −2 1 × 1 = −2 |
0 10000000000 1000000000000000000000000000000000000000000000000000 2 ≙ 4008 0000 0000 0000 16 ≙ +2 1 × 1,1 2 = 11 2 = 3 |
0 10000000001 0000000000000000000000000000000000000000000000000000 2 ≙ 4010 0000 0000 0000 16 ≙ +2 2 × 1 = 100 2 = 4 |
0 10000000001 0100000000000000000000000000000000000000000000000000 2 ≙ 4014 0000 0000 0000 16 ≙ +2 2 × 1,01 2 = 101 2 = 5 |
0 10000000001 1000000000000000000000000000000000000000000000000000 2 ≙ 4018 0000 0000 0000 16 ≙ +2 2 × 1,1 2 = 110 2 = 6 |
0 10000000011 011100000000000000000000000000000000000000000000000 2 ≙ 4037 0000 0000 0000 16 ≙ +2 4 × 1,0111 2 = 10111 = 23 |
0 01111111000 100000000000000000000000000000000000000000000000000 2 ≙ 3F88 0000 0000 0000 16 ≙ +2 −7 × 1,1 2 = 0,00000011 2 = 0,01171875 (3/256) |
0 00000000000 0000000000000000000000000000000000000000000000000000001 2 ≙ 0000 0000 0000 0001 16 ≙ +2 −1022 × 2 −52 = 2 −1074 ≈ 4,9406564584124654 × 10 −324 (Mín. doble positivo subnormal) |
0 00000000000 11111111111111111111111111111111111111111111111111111 2 ≙ 000F FFFF FFFF FFFF 16 ≙ +2 −1022 × (1 − 2 −52 ) ≈ 2,2250738585072009 × 10 −308 (máximo doble subnormal) |
0 00000000001 000000000000000000000000000000000000000000000000000000 2 ≙ 0010 0000 0000 0000 16 ≙ +2 −1022 × 1 ≈ 2,2250738585072014 × 10 −308 (mín. doble positivo normal) |
0 11111111110 11111111111111111111111111111111111111111111111111111 2 ≙ 7FEF FFFF FFFF FFFF 16 ≙ +2 1023 × (1 + (1 − 2 −52 )) ≈ 1,7976931348623157 × 10 308 (Máx. doble) |
0 00000000000 0000000000000000000000000000000000000000000000000000 2 ≙ 0000 0000 0000 0000 16 ≙ +0 |
1 00000000000 0000000000000000000000000000000000000000000000000000 2 ≙ 8000 0000 0000 0000 16 ≙ −0 |
0 11111111111 000000000000000000000000000000000000000000000000000000 2 ≙ 7FF0 0000 0000 0000 16 ≙ +∞ (infinito positivo) |
1 11111111111 000000000000000000000000000000000000000000000000000000 2 ≙ FFF0 0000 0000 0000 16 ≙ −∞ (infinito negativo) |
0 11111111111 0000000000000000000000000000000000000000000000000000001 2 ≙ 7FF0 0000 0000 0001 16 ≙ NaN (sNaN en la mayoría de los procesadores, como x86 y ARM) |
0 11111111111 100000000000000000000000000000000000000000000000000000001 2 ≙ 7FF8 0000 0000 0001 16 ≙ NaN (qNaN en la mayoría de los procesadores, como x86 y ARM) |
0 11111111111 1111111111111111111111111111111111111111111111111111 2 ≙ 7FFF FFFF FFFF FFFF 16 ≙ NaN (una codificación alternativa de NaN) |
0 01111111101 0101010101010101010101010101010101010101010101010101 2 = 3FD5 5555 5555 5555 16 ≙ +2 −2 × (1 + 2 −2 + 2 −4 + ... + 2 −52 ) ≈ 1/3 |
0 10000000000 1001001000011111101101010100010001000010110100011000 2 = 4009 21FB 5444 2D18 16 ≈ pi |
Las codificaciones de qNaN y sNaN no están completamente especificadas en IEEE 754 y dependen del procesador. La mayoría de los procesadores, como la familia x86 y los procesadores de la familia ARM , utilizan el bit más significativo del campo de significando para indicar un NaN silencioso; esto es lo que recomienda IEEE 754. Los procesadores PA-RISC utilizan el bit para indicar un NaN de señalización.
De forma predeterminada, 1/3 redondea hacia abajo, en lugar de hacia arriba como la precisión simple , debido al número impar de bits en la mantisa.
Más detalladamente:
Dada la representación hexadecimal 3FD5 5555 5555 5555 16 , Signo = 0 Exponente = 3FD 16 = 1021 Sesgo del exponente = 1023 (valor constante; ver arriba) Fracción = 5 5555 5555 5555 16 Valor = 2 (Exponente − Sesgo del exponente) × 1.Fracción: tenga en cuenta que la fracción no se debe convertir a decimal aquí = 2 −2 × (15 5555 5555 5555 16 × 2 −52 ) = 2 −54 × 15 5555 5555 5555 16 = 0,333333333333333314829616256247390992939472198486328125 ≈ 1/3
El uso de variables de punto flotante de doble precisión suele ser más lento que trabajar con sus contrapartes de precisión simple. Un área de la informática donde esto es un problema particular es el código paralelo que se ejecuta en GPU. Por ejemplo, al utilizar la plataforma CUDA de NVIDIA , los cálculos con doble precisión pueden tardar, según el hardware, entre 2 y 32 veces más en completarse en comparación con los que se realizan con precisión simple . [4]
Además, muchas funciones matemáticas (por ejemplo, sin, cos, atan2, log, exp y sqrt) necesitan más cálculos para dar resultados precisos de doble precisión y, por lo tanto, son más lentas.
Los dobles se implementan en muchos lenguajes de programación de diferentes maneras, como las siguientes: En procesadores con solo precisión dinámica, como x86 sin SSE2 (o cuando no se utiliza SSE2, por motivos de compatibilidad) y con precisión extendida utilizada de forma predeterminada, el software puede tener dificultades para cumplir con algunos requisitos.
C y C++ ofrecen una amplia variedad de tipos aritméticos . Los estándares no exigen precisión doble (excepto el anexo F opcional de C99 , que cubre la aritmética IEEE 754), pero en la mayoría de los sistemas, el double
tipo corresponde a precisión doble. Sin embargo, en x86 de 32 bits con precisión extendida por defecto, algunos compiladores pueden no cumplir con el estándar C o la aritmética puede sufrir redondeo doble . [5]
Fortran proporciona varios tipos enteros y reales, y el tipo de 64 bits real64
, accesible a través del módulo intrínseco de Fortran iso_fortran_env
, corresponde a la doble precisión.
Common Lisp proporciona los tipos SHORT-FLOAT, SINGLE-FLOAT, DOUBLE-FLOAT y LONG-FLOAT. La mayoría de las implementaciones proporcionan SINGLE-FLOAT y DOUBLE-FLOAT con los demás tipos como sinónimos apropiados. Common Lisp proporciona excepciones para detectar desbordamientos y subdesbordamientos de punto flotante, y la excepción de punto flotante inexacta, según IEEE 754. No se describen infinitos ni NaN en el estándar ANSI, sin embargo, varias implementaciones los proporcionan como extensiones.
En Java , antes de la versión 1.2, todas las implementaciones debían cumplir con el estándar IEEE 754. La versión 1.2 permitió que las implementaciones aportaran precisión adicional en los cálculos intermedios para plataformas como x87 . Por lo tanto, se introdujo un modificador strictfp para aplicar cálculos IEEE 754 estrictos. El punto flotante estricto se ha restaurado en Java 17. [6]
Como lo especifica el estándar ECMAScript , toda la aritmética en JavaScript se realizará utilizando aritmética de punto flotante de doble precisión. [7]
El formato de codificación de datos JSON admite valores numéricos y la gramática a la que deben ajustarse las expresiones numéricas no tiene límites en cuanto a la precisión o el rango de los números así codificados. Sin embargo, la RFC 8259 advierte que, dado que los números de IEEE 754 binary64 están ampliamente implementados, se puede lograr una buena interoperabilidad mediante implementaciones que procesen JSON si no esperan más precisión o rango que el que ofrece binary64. [8]
Rust y Zig tienen el f64
tipo de datos. [9] [10]