Aritmética de punto flotante

Compartir Imprimir Citar
aproximación de la computadora para números reales
Una computadora programable electromecánica temprana, el Z3, incluía aritmética de punto flotante (replicar en exhibición en el Museo Deutsches en Munich).

En computación, la aritmética de punto flotante (FP) es una aritmética que representa números reales de forma aproximada, utilizando un número entero con una precisión fija, llamado significado, escalado por un exponente entero de una base fija. Por ejemplo, 12,345 se puede representar como un número de coma flotante en base diez:

12.345=12345⏟ ⏟ significando× × 10⏟ ⏟ base− − 3⏞ ⏞ exponente{displaystyle 12.345=underbrace {12345} _{text{significand}times underbrace {10} _{text{base}}!!!!! {-3} {fnMicrosoft}}

En la práctica, la mayoría de los sistemas de punto flotante utilizan la base dos, aunque también es común la base diez (punto flotante decimal).

El término coma flotante se refiere al hecho de que la base del número puede "flotar" en cualquier lugar a la izquierda, a la derecha o entre los dígitos significativos del número. Esta posición está indicada por el exponente, por lo que el punto flotante puede considerarse una forma de notación científica.

Se puede usar un sistema de punto flotante para representar, con un número fijo de dígitos, números de muy diferentes órdenes de magnitud, como el número de metros entre galaxias o entre protones en un átomo. Por esta razón, la aritmética de punto flotante se usa a menudo para permitir números reales muy pequeños y muy grandes que requieren tiempos de procesamiento rápidos. El resultado de este rango dinámico es que los números que se pueden representar no están espaciados uniformemente; la diferencia entre dos números consecutivos representables varía con su exponente.

Números de puntos flotantes de una sola precisión en una línea número: las líneas verdes marcan valores representables.
Versión aumentada arriba mostrando ambos signos de valores representables

A lo largo de los años, se han utilizado en las computadoras una variedad de representaciones de punto flotante. En 1985, se estableció el estándar IEEE 754 para la aritmética de punto flotante y, desde la década de 1990, las representaciones que se encuentran con más frecuencia son las definidas por el IEEE.

La velocidad de las operaciones de punto flotante, comúnmente medida en términos de FLOPS, es una característica importante de un sistema informático, especialmente para aplicaciones que involucran cálculos matemáticos intensivos.

Una unidad de punto flotante (FPU, coloquialmente un coprocesador matemático) es una parte de un sistema informático especialmente diseñado para realizar operaciones con números de punto flotante.

Resumen

Números de coma flotante

La representación de un número especifica alguna forma de codificar un número, generalmente como una cadena de dígitos.

Existen varios mecanismos mediante los cuales las cadenas de dígitos pueden representar números. En la notación matemática común, la cadena de dígitos puede tener cualquier longitud y la ubicación del punto de base se indica colocando un 'punto' explícito. carácter (punto o coma) allí. Si no se especifica el punto de base, la cadena representa implícitamente un número entero y el punto de base no declarado estaría fuera del extremo derecho de la cadena, al lado del dígito menos significativo. En los sistemas de punto fijo, se especifica una posición en la cuerda para el punto de base. Entonces, un esquema de punto fijo podría ser usar una cadena de 8 dígitos decimales con el punto decimal en el medio, donde "00012345" representaría 0001.2345.

En notación científica, el número dado está escalado por una potencia de 10, por lo que se encuentra dentro de un cierto rango, generalmente entre 1 y 10, con el punto de base que aparece inmediatamente después del primer dígito. El factor de escala, como una potencia de diez, se indica por separado al final del número. Por ejemplo, el período orbital de la luna Io de Júpiter es 152.853,5047 segundos, un valor que se representaría en notación científica de forma estándar como 1.528535047×105 segundos.

La representación de punto flotante es similar en concepto a la notación científica. Lógicamente, un número de punto flotante consta de:

Para derivar el valor del número de coma flotante, el significando se multiplica por la base elevada a la potencia del exponente, equivalente a desplazar el punto de base de su posición implícita en un número de lugares igual al valor del exponente, hacia la derecha si el exponente es positivo o hacia la izquierda si el exponente es negativo.

Usando la base 10 (la conocida notación decimal) como ejemplo, el número 152,853.5047, que tiene diez dígitos decimales de precisión, se representa como la mantisa 1,528,535,047 junto con 5 como exponente. Para determinar el valor real, se coloca un punto decimal después del primer dígito de la mantisa y el resultado se multiplica por 105 para dar 1.528535047×105, o 152,853.5047. Al almacenar dicho número, no es necesario almacenar la base (10), ya que será la misma para todo el rango de números admitidos y, por lo tanto, se puede inferir.

Simbólicamente, este valor final es:

sbp− − 1× × be,{fnMicroc} {fnMicrosoft Sans Serif}

donde s es la mantisa (ignorando cualquier punto decimal implícito), p es la precisión (el número de dígitos en la mantisa), b es la base (en nuestro ejemplo, este es el número diez), y e es el exponente.

Históricamente, se han utilizado varias bases numéricas para representar números de punto flotante, con base dos (binario) siendo la más común, seguida de la base diez (coma flotante decimal), y otras variedades menos comunes, como la base dieciséis (coma flotante hexadecimal), la base ocho (coma flotante octal), la base cuatro (coma flotante cuaternaria), la base tres (punto flotante ternario balanceado) e incluso base 256 y base 65,536.

Un número de coma flotante es un número racional, porque se puede representar como un número entero dividido por otro; por ejemplo 1.45× 103 es (145/100)×1000 o 145.000/100. La base determina las fracciones que se pueden representar; por ejemplo, 1/5 no se puede representar exactamente como un número de punto flotante usando una base binaria, pero 1/5 se puede representar exactamente usando una base decimal (0.2, o 2×10−1). Sin embargo, 1/3 no se puede representar exactamente ni en binario (0,010101...) ni en decimal (0,333...), pero en base 3 es trivial (0,1 o 1×3−1). Las ocasiones en que ocurren expansiones infinitas dependen de la base y sus factores primos.

La forma en que el significado (incluyendo su signo) y el exponente se almacenan en un ordenador es dependiente de la implementación. Los formatos comunes de IEEE se describen en detalle más tarde y en otros lugares, pero como ejemplo, en la representación binaria de un solo punto de vista (32 bits), p=24{displaystyle p=24}, y así el significado es una cadena de 24 bits. Por ejemplo, los primeros 33 bits del número π son:

110010010000111111011010¿Qué? ¿Qué? 101000100.{displaystyle 11001001 00001111 1101101{underline {0} 10100010 0.}

En esta expansión binaria, indiquemos las posiciones desde 0 (bit más a la izquierda o bit más significativo) hasta 32 (bit más a la derecha). La mantisa de 24 bits se detendrá en la posición 23, que se muestra como el bit subrayado 0 arriba. El siguiente bit, en la posición 24, se llama bit redondo o bit redondo. Se utiliza para redondear la aproximación de 33 bits al número de 24 bits más cercano (existen reglas específicas para valores intermedios, que no es el caso aquí). Este bit, que es 1 en este ejemplo, se suma al número entero formado por los 24 bits más a la izquierda, dando:

110010010000111111011011¿Qué? ¿Qué? .{displaystyle 11001001 00001111 1101101{underline {1}}}

Cuando esto se almacena en la memoria utilizando la codificación IEEE 754, se convierte en el significado s. Se supone que la mantisa tiene un punto binario a la derecha del bit más a la izquierda. Entonces, la representación binaria de π se calcula de izquierda a derecha de la siguiente manera:

().. n=0p− − 1bitn× × 2− − n)× × 2e=()1× × 2− − 0+1× × 2− − 1+0× × 2− − 2+0× × 2− − 3+1× × 2− − 4+⋯ ⋯ +1× × 2− − 23)× × 21.. 1.5707964× × 2.. 3.1415928{displaystyle {begin{aligned} ### {n=0}{p-1} {text{bit}_{n}times 2^{-n}right)times 2^{e}={} {left(1times 2^{-0}+1times 2^{-1}+0times 2^{-2}+0times 2^{-3}+1times 2^{-4}+cdots +1times 2^{-23}right)times 2^{1}\\approx {}}5707964times 2\\approx {}

donde p es la precisión (24 en este ejemplo), n es la posición del bit de la mantisa desde la izquierda (comenzando en 0 y terminando en 23 aquí) y e es el exponente (1 en este ejemplo).

Se puede exigir que el dígito más significativo de la mantisa de un número distinto de cero sea distinto de cero (excepto cuando el exponente correspondiente sea menor que el mínimo). Este proceso se llama normalización. Para formatos binarios (que usa solo los dígitos 0 y 1), este dígito distinto de cero es necesariamente 1. Por lo tanto, no necesita estar representado en la memoria; permitiendo que el formato tenga un poco más de precisión. Esta regla se denomina convención de bit inicial, convención de bit implícita, convención de bit oculta o convención de bit asumida.

Alternativas a los números de coma flotante

La representación de punto flotante es, con mucho, la forma más común de representar en computadoras una aproximación a los números reales. Sin embargo, hay alternativas:

Historia

Leonardo Torres y Quevedo, quien propuso una forma de punto flotante en 1914

En 1914, Leonardo Torres y Quevedo propuso una forma de punto flotante en el curso de discutir su diseño para una calculadora electromecánica especial. En 1938, Konrad Zuse de Berlín completó el Z1, el primer ordenador mecánico binario programable; utiliza una representación binaria de 24 bits con un exponente de 7 bits firmado, un significado de 17 bits (incluyendo un bit implícito), y un bit de señal. El Z3, basado en relés más fiable, completado en 1941, tiene representaciones tanto para los infinitos positivos como negativos; en particular, implementa operaciones definidas con infinito, como 1/JUEGO JUEGO =0{displaystyle ^{1}/_{infty}=0}, y se detiene en operaciones indefinidas, como 0× × JUEGO JUEGO {displaystyle 0times infty}.

Konrad Zuse, arquitecto de la computadora Z3, que utiliza una representación binaria de 22 bits de punto flotante

Zuse también propuso, pero no completó, cuidadosamente redondeado aritmética de punto flotante que incluye ± ± JUEGO JUEGO {displaystyle pm infty } y representaciones de NaN, anticipando características de la norma IEEE por cuatro décadas. En cambio, von Neumann recomendó contra los números de puntos flotantes para la máquina IAS de 1951, argumentando que la aritmética de punto fijo es preferible.

La primera computadora comercial con hardware de punto flotante fue la computadora Z4 de Zuse, diseñada entre 1942 y 1945. En 1946, Bell Laboratories presentó Mark V, que implementó números decimales de punto flotante.

El Pilot ACE tiene aritmética de coma flotante binaria y entró en funcionamiento en 1950 en el Laboratorio Nacional de Física del Reino Unido. Treinta y tres se vendieron comercialmente más tarde como English Electric DEUCE. La aritmética en realidad está implementada en el software, pero con una velocidad de reloj de un megahercio, la velocidad de las operaciones de punto flotante y punto fijo en esta máquina fue inicialmente más rápida que la de muchas computadoras de la competencia.

El IBM 704 producido en masa siguió en 1954; introdujo el uso de un exponente sesgado. Durante muchas décadas después de eso, el hardware de punto flotante era típicamente una característica opcional, y las computadoras que lo tenían se decía que eran 'computadoras científicas', o que tenían 'computación científica'. (SC) (ver también Extensiones para Computación Científica (XSC)). No fue sino hasta el lanzamiento del Intel i486 en 1989 que las computadoras personales de propósito general tuvieron la capacidad de punto flotante en el hardware como característica estándar.

La serie UNIVAC 1100/2200, presentada en 1962, admitía dos representaciones de punto flotante:

El IBM 7094, también presentado en 1962, admitía representaciones de precisión simple y precisión doble, pero sin relación con las representaciones de UNIVAC. De hecho, en 1964, IBM introdujo representaciones de punto flotante hexadecimal en sus mainframes System/360; estas mismas representaciones todavía están disponibles para su uso en sistemas z/Architecture modernos. En 1998, IBM implementó aritmética binaria de punto flotante compatible con IEEE en sus mainframes; en 2005, IBM también agregó aritmética de punto flotante decimal compatible con IEEE.

Al principio, las computadoras usaban muchas representaciones diferentes para los números de punto flotante. La falta de estandarización a nivel de mainframe era un problema continuo a principios de la década de 1970 para quienes escribían y mantenían el código fuente de nivel superior; estos estándares de punto flotante del fabricante diferían en el tamaño de las palabras, las representaciones y el comportamiento de redondeo y la precisión general de las operaciones. La compatibilidad de punto flotante entre múltiples sistemas informáticos necesitaba desesperadamente estandarizarse a principios de la década de 1980, lo que condujo a la creación del estándar IEEE 754 una vez que la palabra de 32 bits (o 64 bits) se convirtió en un lugar común. Este estándar se basó significativamente en una propuesta de Intel, que estaba diseñando el coprocesador numérico i8087; Motorola, que estaba diseñando el 68000 casi al mismo tiempo, también brindó una contribución significativa.

En 1989, el matemático e informático William Kahan fue galardonado con el Premio Turing por ser el arquitecto principal detrás de esta propuesta; fue ayudado por su alumno Jerome Coonen y un profesor invitado, Harold Stone.

Entre las innovaciones x86 se encuentran estas:

Rango de números de coma flotante

Un número de punto flotante consta de dos componentes de punto fijo, cuyo rango depende exclusivamente del número de bits o dígitos en su representación. Mientras que los componentes dependen linealmente de su rango, el rango de coma flotante depende linealmente del rango del significado y exponencialmente del rango del componente del exponente, lo que otorga un rango notablemente más amplio al número.

En un sistema informático típico, un número de punto flotante binario de doble precisión (64 bits) tiene un coeficiente de 53 bits (incluido 1 bit implícito), un exponente de 11 bits y 1 bit de signo. Dado que 210 = 1024, el rango completo de números de punto flotante normales positivos en este formato es de 2−1022 ≈ 2 × 10−308 a aproximadamente 21024 ≈ 2 × 10308.

El número de números normales de coma flotante en un sistema (B, P, L, U) dónde

es 2()B− − 1)()BP− − 1)()U− − L+1){displaystyle 2left(B-1right)left(B^{P-1}right)left(U-L+1right)}.

Hay un número de punto flotante normal positivo más pequeño,

Nivel de subfluencia = UFL = BL{displaystyle B^{L},

que tiene un 1 como primer dígito y un 0 para los dígitos restantes de la mantisa, y el valor más pequeño posible para el exponente.

Hay un número de punto flotante más grande,

Nivel de desbordamiento = DEL = ()1− − B− − P)()BU+1){displaystyle left(1-B^{-P}right)left(B^{U+1}right)},

que tiene B − 1 como el valor de cada dígito de la mantisa y el mayor valor posible para el exponente.

Además, existen valores representables estrictamente entre −UFL y UFL. A saber, ceros positivos y negativos, así como números subnormales.

IEEE 754: punto flotante en las computadoras modernas

El IEEE estandarizó la representación informática para números binarios de coma flotante en IEEE 754 (también conocido como IEC 60559) en 1985. Casi todas las máquinas modernas siguen este primer estándar. Se revisó en 2008. Los mainframes de IBM admiten el formato de punto flotante hexadecimal propio de IBM y el punto flotante decimal IEEE 754-2008 además del formato binario IEEE 754. La serie Cray T90 tenía una versión IEEE, pero el SV1 todavía usa el formato de punto flotante Cray.

El estándar proporciona muchos formatos estrechamente relacionados, que difieren solo en algunos detalles. Cinco de estos formatos se denominan formatos básicos y otros se denominan formatos de precisión extendida y formato de precisión extensible. Tres formatos son especialmente utilizados en hardware y lenguajes informáticos:

Aumentar la precisión de la representación de punto flotante generalmente reduce la cantidad de error de redondeo acumulado causado por los cálculos intermedios. Los formatos IEEE menos comunes incluyen:

Cualquier número entero con valor absoluto menor que 224 se puede representar exactamente en el formato de precisión simple, y cualquier número entero con valor absoluto menor que 253 se puede representar exactamente representado en el formato de doble precisión. Además, se puede representar una amplia gama de potencias de 2 veces dicho número. Estas propiedades a veces se usan para datos puramente enteros, para obtener enteros de 53 bits en plataformas que tienen flotantes de doble precisión pero solo enteros de 32 bits.

El estándar especifica algunos valores especiales y su representación: infinito positivo (+∞), infinito negativo (−∞), un cero negativo (−0) distinto del cero ordinario ("positivo"), y "no es un número" valores (NaN).

La comparación de números de coma flotante, según lo define el estándar IEEE, es un poco diferente de la comparación de enteros habitual. El cero negativo y el positivo se comparan como iguales, y cada NaN se compara como desigual con todos los valores, incluido él mismo. Todos los números de coma flotante finitos son estrictamente menores que +∞ y estrictamente mayores que −∞, y están ordenados de la misma como sus valores (en el conjunto de los números reales).

Representación interna

Los números de coma flotante generalmente se empaquetan en un dato de computadora como el bit de signo, el campo del exponente y la mantisa o mantisa, de izquierda a derecha. Para los formatos binarios IEEE 754 (básico y extendido) que tienen implementaciones de hardware existentes, se distribuyen de la siguiente manera:

Tipo Signatura Exponent Campo significativo Total bits Sesgo exponente Precisión de bits Número de dígitos decimales
Media (IEEE 754-2008) 1 5 10 16 15 11 ~3.3
Individual 1 8 23 32 127 24 ~7.2
Doble 1 11 52 64 1023 53 ~15.9
x86 precisión extendida 1 15 64 80 16383 64 ~19.2
Quad 1 15 112 128 16383 113 ~34.0

Si bien el exponente puede ser positivo o negativo, en formatos binarios se almacena como un número sin signo que tiene un "sesgo" añadido a la misma. Los valores de todos los 0 en este campo están reservados para los ceros y los números subnormales; los valores de todos los 1 están reservados para los infinitos y NaN. El rango de exponente para números normales es [−126, 127] para precisión simple, [−1022, 1023] para doble o [−16382, 16383] para cuádruple. Los números normales excluyen valores subnormales, ceros, infinitos y NaN.

En los formatos de intercambio binario IEEE, el primer bit de un significado normalizado no se almacena realmente en el dato de la computadora. Se llama el "oculto" o "implícito" bit. Debido a esto, el formato de precisión simple en realidad tiene una significancia con 24 bits de precisión, el formato de precisión doble tiene 53 y el cuádruple tiene 113.

Por ejemplo, arriba se mostró que π, redondeado a 24 bits de precisión, tiene:

La suma del sesgo del exponente (127) y el exponente (1) es 128, por lo que esto se representa en el formato de precisión simple como

Un ejemplo de un diseño para punto flotante de 32 bits es

Float example.svg

y el diseño de 64 bits ("doble") es similar.

Otros formatos notables de coma flotante

Además de los formatos estándar IEEE 754 ampliamente utilizados, se utilizan, o se han utilizado, otros formatos de punto flotante en ciertas áreas específicas de dominio.

Bfloat16, TensorFloat-32, y los dos formatos FP8, en comparación con IEEE 754 formatos de media precisión y una sola precisión
Tipo Signatura Exponent Trailing significand field Total bits
FP8 (E4M3) 1 4 3 8
FP8 (E5M2) 1 5 2 8
Media precisión 1 5 10 16
Bfloat16 1 8 7 16
TensorFloat-32 1 8 10 19
Una sola precisión 1 8 23 32

Números representables, conversión y redondeo

Por su naturaleza, todos los números expresados en formato de punto flotante son números racionales con una expansión final en la base correspondiente (por ejemplo, una expansión decimal final en base 10 o una expansión binaria final en base 2). Los números irracionales, como π o √2, o los números racionales no terminales, deben aproximarse. El número de dígitos (o bits) de precisión también limita el conjunto de números racionales que se pueden representar con exactitud. Por ejemplo, el número decimal 123456789 no se puede representar con exactitud si solo se dispone de ocho dígitos decimales de precisión (se redondearía a uno de los dos valores representables intermedios, 12345678 × 101 o 12345679 × 101), lo mismo se aplica a los dígitos que no terminan (.5 para ser redondeado a.55555555 o.55555556).

Cuando un número se representa en algún formato (como una cadena de caracteres) que no es una representación nativa de coma flotante admitida en una implementación informática, será necesario realizar una conversión antes de que pueda usarse en esa implementación. Si el número se puede representar exactamente en el formato de punto flotante, la conversión es exacta. Si no hay una representación exacta, la conversión requiere elegir qué número de punto flotante usar para representar el valor original. La representación elegida tendrá un valor diferente al original, y el valor así ajustado se denomina valor redondeado.

Que un número racional tenga o no una expansión terminal depende de la base. Por ejemplo, en base 10 el número 1/2 tiene una expansión terminal (0,5) mientras que el número 1/3 no (0,333...). En base 2, solo terminan los racionales con denominadores que son potencias de 2 (como 1/2 o 3/16). Cualquier racional con un denominador que tenga un factor primo distinto de 2 tendrá una expansión binaria infinita. Esto significa que es posible que los números que parecen cortos y exactos cuando se escriben en formato decimal deban aproximarse cuando se convierten a punto flotante binario. Por ejemplo, el número decimal 0.1 no se puede representar en punto flotante binario de precisión finita; la representación binaria exacta tendría un "1100" secuencia continua sin fin:

e = 4); s = 110011001100110011001100110011001111...

donde, como anteriormente, s es la mantisa y e es el exponente.

Cuando se redondea a 24 bits, se convierte en

e = 4); s = 110011001100110011001101,

que en realidad es 0.100000001490116119384765625 en decimal.

Como ejemplo adicional, el número real π, representado en binario como una secuencia infinita de bits es

11.00100100001111110101010001000010110100011000011010011...

pero es

11.0010010000111111011

cuando se aproxima redondeando a una precisión de 24 bits.

En punto flotante binario de precisión simple, esto se representa como s = 1.10010010000111111011011 con e = 1. Esto tiene un valor decimal de

3.1415927410125732421875,

mientras que una aproximación más precisa del verdadero valor de π es

3.141592653589793238462643387950...

El resultado del redondeo difiere del valor real en aproximadamente 0,03 partes por millón y coincide con la representación decimal de π en los primeros 7 dígitos. La diferencia es el error de discretización y está limitada por el épsilon de la máquina.

La diferencia aritmética entre dos números de punto flotante representable consecutivos que tienen el mismo exponente se denomina unidad en último lugar (ULP). Por ejemplo, si no hay un número representable entre los números representables 1.45a70c22hex y 1.45a70c24hex, el ULP es 2×16−8, o 2−31. Para números con un exponente de base 2 parte de 0, es decir, números con un valor absoluto superior o igual a 1 pero inferior a 2, un ULP es exactamente 2−23 o aproximadamente 10− 7 en precisión simple y exactamente 2−53 o aproximadamente 10−16 en precisión doble. El comportamiento obligatorio del hardware compatible con IEEE es que el resultado esté dentro de la mitad de un ULP.

Modos de redondeo

El redondeo se usa cuando el resultado exacto de una operación de punto flotante (o una conversión al formato de punto flotante) necesitaría más dígitos que dígitos en la mantisa. IEEE 754 requiere redondeo correcto: es decir, el resultado redondeado es como si se usara una aritmética infinitamente precisa para calcular el valor y luego se redondeara (aunque en la implementación solo se necesitan tres bits adicionales para asegurar esto). Hay varios esquemas de redondeo diferentes (o modos de redondeo). Históricamente, el truncamiento era el enfoque típico. Desde la introducción de IEEE 754, el método predeterminado (redondear al más cercano, se vincula a par, a veces llamado redondeo bancario) se usa con más frecuencia. Este método redondea el resultado ideal (infinitamente preciso) de una operación aritmética al valor representable más cercano y da esa representación como resultado. En caso de empate, se elige el valor que haría que la mantisa terminara en un dígito par. El estándar IEEE 754 requiere que se aplique el mismo redondeo a todas las operaciones algebraicas fundamentales, incluidas la raíz cuadrada y las conversiones, cuando hay un resultado numérico (no NaN). Significa que los resultados de las operaciones IEEE 754 están completamente determinados en todos los bits del resultado, excepto en la representación de NaN. (Las funciones de 'Biblioteca', como el coseno y el logaritmo, no son obligatorias).

También hay disponibles opciones de redondeo alternativas. IEEE 754 especifica los siguientes modos de redondeo:

Los modos alternativos son útiles cuando se debe limitar la cantidad de error que se introduce. Las aplicaciones que requieren un error acotado son el punto flotante de precisión múltiple y la aritmética de intervalos. Los modos de redondeo alternativos también son útiles para diagnosticar la inestabilidad numérica: si los resultados de una subrutina varían sustancialmente entre el redondeo a + y − infinito, es probable que sea numéricamente inestable y se vea afectada por un error de redondeo.

Conversión de binario a decimal con un número mínimo de dígitos

Convertir un número de punto flotante binario de doble precisión en una cadena decimal es una operación común, pero un algoritmo que produce resultados que son precisos y mínimos no apareció impreso hasta 1990, con Steele y White's Dragon4. Algunas de las mejoras desde entonces incluyen:

Muchos tiempos de ejecución de lenguajes modernos usan Grisu3 con un respaldo de Dragon4.

Conversión de decimal a binario

El problema de analizar una cadena decimal en una representación FP binaria es complejo, y no apareció un analizador preciso hasta el trabajo de Clinger de 1990 (implementado en dtoa.c). El trabajo adicional también ha progresado en la dirección de un análisis más rápido.

Operaciones de punto flotante

Para facilitar la presentación y la comprensión, en los ejemplos se utilizará la base decimal con una precisión de 7 dígitos, como en el formato IEEE 754 decimal32. Los principios fundamentales son los mismos en cualquier raíz o precisión, excepto que la normalización es opcional (no afecta el valor numérico del resultado). Aquí, s denota el significado y e denota el exponente.

Sumas y restas

Un método simple para sumar números de punto flotante es representarlos primero con el mismo exponente. En el siguiente ejemplo, el segundo número se desplaza tres dígitos hacia la derecha y luego se procede con el método de suma habitual:

 123456.7 = 1,234567 × 10^5
101.7654 = 1.017654 × 10^2 = 0,001017654 × 10^5
 Por lo tanto:
123456.7 + 101.7654 = (1.234567 × 10^5) + (1.017654 × 10^2)
= (1.234567 × 10^5) + (0.001017654 × 10^5)
= (1.234567 + 0.001017654) × 10^5
= 1.235584654 × 10^5

En detalle:

 e=5; s=1.234567 (123456.7)
+ e=2; s=1.017654 (101.7654)
 e=5; s=1.234567
+ e=5; s=0.001017654 (después del cambio)
--------------------
e=5; s=1.235584654 (suma real: 123558.4654)

Este es el verdadero resultado, la suma exacta de los operandos. Se redondeará a siete dígitos y luego se normalizará si es necesario. el resultado final es

 e=5; s=1.235585 (suma final: 123558.5)

Los tres dígitos más bajos del segundo operando (654) se pierden esencialmente. Este es un error de redondeo. En casos extremos, la suma de dos números distintos de cero puede ser igual a uno de ellos:

 e=5; s=1.234567
+ e=−3; s=9.876543
 e=5; s=1.234567
+ e=5; s=0.00000009876543 (después del cambio)
----
e=5; s=1.23456709876543 (suma real)
e=5; s=1.234567 (después de redondeo y normalización)

En los ejemplos conceptuales anteriores, parecería que el sumador necesitaría proporcionar una gran cantidad de dígitos adicionales para garantizar el redondeo correcto; sin embargo, para la suma o resta binaria utilizando técnicas de implementación cuidadosas, solo es necesario llevar más allá un bit de protección, un bit de redondeo y un bit de adherencia adicional. la precisión de los operandos.

Otro problema de pérdida de significado ocurre cuando se restan aproximaciones a dos números casi iguales. En el siguiente ejemplo e = 5; s = 1,234571 y e = 5; s = 1,234567 son aproximaciones a los racionales 123457,1467 y 123456,659.

 e=5; s=1.234571
− e=5; s=1.234567
.
e=5; s=0.000004
e=-1; s=4.000000 (después de redondeo y normalización)

La diferencia de punto flotante se calcula exactamente porque los números están cerca; el lema de Sterbenz lo garantiza, incluso en caso de desbordamiento cuando se admite el desbordamiento gradual. A pesar de esto, la diferencia de los números originales es e = −1; s = 4,877000, que difiere en más de un 20 % de la diferencia e = −1; s = 4,000000 de las aproximaciones. En casos extremos, se pueden perder todos los dígitos significativos de precisión. Esta cancelación ilustra el peligro de suponer que todos los dígitos de un resultado calculado son significativos. Tratar con las consecuencias de estos errores es un tema de análisis numérico; véase también Problemas de precisión.

Multiplicación y división

Para multiplicar, se multiplican los significados mientras se suman los exponentes, y el resultado se redondea y normaliza.

 e=3; s=4.734612
× e=5; s=5.417242
-----
e=8; s=25.648538980104 (producto real)
e=8; s=25.64854 (después de redondear)
e=9; s=2.564854 (después de la normalización)

Del mismo modo, la división se logra restando el exponente del divisor del exponente del dividendo y dividiendo el significado del dividendo por el significado del divisor.

No hay problemas de cancelación o absorción con la multiplicación o la división, aunque pueden acumularse pequeños errores a medida que las operaciones se realizan en sucesión. En la práctica, la forma en que se llevan a cabo estas operaciones en lógica digital puede ser bastante compleja (consulte el algoritmo de multiplicación de Booth y el algoritmo de división). Para conocer un método rápido y sencillo, consulte el método de Horner.

Sintaxis literal

Los literales de los números de punto flotante dependen de los idiomas. Por lo general, usan e o E para indicar notación científica. El lenguaje de programación C y el estándar IEEE 754 también definen una sintaxis literal hexadecimal con un exponente de base 2 en lugar de 10. En lenguajes como C, cuando se omite el exponente decimal, se necesita un punto decimal para diferenciarlos de los números enteros. Otros lenguajes no tienen un tipo entero (como JavaScript) o permiten la sobrecarga de tipos numéricos (como Haskell). En estos casos, las cadenas de dígitos como 123 también pueden ser literales de coma flotante.

Ejemplos de literales de coma flotante son:

Tratamiento de casos excepcionales

El cálculo de punto flotante en una computadora puede encontrarse con tres tipos de problemas:

Antes del estándar IEEE, tales condiciones generalmente causaban que el programa terminara o desencadenaban algún tipo de trampa que el programador podría atrapar. El funcionamiento de esto dependía del sistema, lo que significa que los programas de punto flotante no eran portátiles. (El término "excepción" como se usa en IEEE 754 es un término general que significa una condición excepcional, que no es necesariamente un error, y es un uso diferente al que normalmente se define en lenguajes de programación como C++ o Java)., en el que una 'excepción' es un flujo de control alternativo, más cercano a lo que se denomina 'trampa' en la terminología IEEE 754).

Aquí, se analiza el método predeterminado requerido para el manejo de excepciones de acuerdo con IEEE 754 (no se analizan las capturas opcionales de IEEE 754 ni otros modos de "manejo alternativo de excepciones"). Las excepciones aritméticas (de forma predeterminada) deben registrarse en "sticky" bits de bandera de estado. Que sean "pegajosos" significa que no se restablecen con la siguiente operación (aritmética), sino que permanecen configurados hasta que se restablecen explícitamente. El uso de "pegajoso" flags permite que la prueba de condiciones excepcionales se retrase hasta después de una subrutina o expresión de coma flotante completa: sin ellas, las condiciones excepcionales que de otro modo no podrían ignorarse requerirían pruebas explícitas inmediatamente después de cada operación de coma flotante. De forma predeterminada, una operación siempre devuelve un resultado de acuerdo con la especificación sin interrumpir el cálculo. Por ejemplo, 1/0 devuelve +∞, al mismo tiempo que establece el bit indicador de división por cero (este valor predeterminado de ∞ está diseñado para devolver a menudo un resultado finito cuando se usa en operaciones posteriores y, por lo tanto, se ignora de forma segura).

Sin embargo, el estándar IEEE 754 original no recomendaba operaciones para manejar dichos conjuntos de bits de marca de excepción aritmética. Entonces, si bien estos se implementaron en hardware, inicialmente las implementaciones del lenguaje de programación generalmente no proporcionaron un medio para acceder a ellos (aparte del ensamblador). Con el tiempo, algunos estándares de lenguajes de programación (p. ej., C99/C11 y Fortran) se han actualizado para especificar métodos para acceder y cambiar los bits de indicadores de estado. La versión 2008 del estándar IEEE 754 ahora especifica algunas operaciones para acceder y manejar los bits de bandera aritmética. El modelo de programación se basa en un único subproceso de ejecución y su uso por parte de múltiples subprocesos debe manejarse por un medio fuera del estándar (por ejemplo, C11 especifica que las banderas tienen almacenamiento local de subprocesos).

IEEE 754 especifica cinco excepciones aritméticas que deben registrarse en los indicadores de estado ("sticky bits"):

Fig. 1: resistencias en paralelo, con resistencia total Rtot{displaystyle R_{tot}

El valor de retorno predeterminado para cada una de las excepciones está diseñado para dar el resultado correcto en la mayoría de los casos, de tal manera que las excepciones pueden ser ignoradas en la mayoría de los códigos. inexacto devuelve un resultado redondeado correctamente, y corrientes devuelve un valor inferior o igual al menor número normal positivo en magnitud y casi siempre se puede ignorar. divide por cero devuelve el infinito exactamente, que por lo general dividir un número finito y así dar cero, o de otro modo dar un inválido excepción ulteriormente si no, y por lo tanto también se puede ignorar. Por ejemplo, la resistencia efectiva de n resistors en paralelo (ver fig. 1) es dado por RTot=1/()1/R1+1/R2+⋯ ⋯ +1/Rn){displaystyle R_{text{tot}=1/(1/R_{1}+1/R_{2}+cdots +1/R_{n})}. Si un cortocircuito se desarrolla con R1{displaystyle R_{1} establecido a 0, 1/R1{displaystyle 1/R_{1}} volverá +infinito que dará una final Rtot{displaystyle R_{tot} de 0, como se esperaba (ver el ejemplo de fracción continua de IEEE 754 racional de diseño por otro ejemplo).

Las excepciones

Overflow y invalid generalmente no se pueden ignorar, pero no representan necesariamente errores: por ejemplo, una rutina de búsqueda de raíces, como parte de su funcionamiento normal, puede evaluar una función pasada en valores fuera de su dominio, devolviendo NaN y un indicador de excepción no válido para ignorar hasta encontrar un punto de inicio útil.

Problemas de precisión

El hecho de que los números de punto flotante no puedan representar con precisión todos los números reales, y que las operaciones de punto flotante no puedan representar con precisión operaciones aritméticas verdaderas, conduce a muchas situaciones sorprendentes. Esto está relacionado con la precisión finita con la que las computadoras generalmente representan números.

Por ejemplo, la no representabilidad de 0,1 y 0,01 (en binario) significa que el resultado de intentar elevar al cuadrado 0,1 no es ni 0,01 ni el número representable más cercano. En la representación de 24 bits (precisión simple), 0.1 (decimal) se proporcionó anteriormente como e = −4; s = 110011001100110011001101, que es

0.100000001490116119384765625 exactamente.

Al elevar al cuadrado este número se obtiene

0,010000298023226097399174250313080847263336181640625 exactamente.

Cuadrar con hardware de punto flotante de precisión simple (con redondeo) da

0.010000000707805156707763671875 exactamente.

Pero el número representable más cercano a 0.01 es

0,009999776482582092285156250 exactamente.

Además, la no representabilidad de π (y π/2) significa que un intento de cálculo de tan(π/2) no producirá un resultado de infinito, ni se desbordará en los formatos habituales de coma flotante (asumiendo una implementación precisa de tan). Simplemente no es posible que el hardware de coma flotante estándar intente calcular tan(π/2), porque π/2 no se puede representar exactamente. Este cálculo en C:

/* Suficientes dígitos para estar seguros de que obtenemos la aproximación correcta. */doble pi = 3.1415926535897932384626433832795;doble z = #()pi/2.0);

dará un resultado de 16331239353195370.0. En precisión simple (usando la función tanf), el resultado será −22877332.0.

De la misma manera, un intento de cálculo de sin(π) no arrojará cero. El resultado será (aproximadamente) 0.1225×10−15 en doble precisión, o −0.8742×10−7 en precisión simple.

Mientras que la suma y la multiplicación en coma flotante son conmutativas (a + b = b + a y a × b = b × a), no son necesariamente asociativos. Es decir, (a + b) + c no es necesariamente igual a a + (b + c). Usando la aritmética decimal significativa de 7 dígitos:

 a = 1234.567, b = 45.67834, c = 0,0004
 (a + b) + c:
1234.567 a)
+ 45.67834 b)
____________
1280.24534 rondas a 1280.245
 1280.245 (a + b)
+ 0,0004 c)
____________
1280.2454 rondas a 1280.245 ← (a + b) + c
 a + (b + c):
45.67834 b)
+ 0,0004 c)
____________
45.67874
 1234.567 a)
+ 45.67874 (b + c)
____________
1280.24574 rondas a 1280,246 ← a + (b + c)

Tampoco son necesariamente distributivos. Es decir, (a + b) × c puede no ser lo mismo que a × c + b × c:

 1234.567 × 3.333333 = 4115.223
1.234567 × 3.33333333 = 4.115223
4115.223 + 4.115223 = 4119.338
pero
1234.567 + 1,234567 = 1235.802
1235.802 × 3.333333 = 4119.340

Además de la pérdida de significado, la incapacidad para representar números como π y 0,1 con exactitud, y otras imprecisiones leves, pueden ocurrir los siguientes fenómenos:

  • Cancelación: la resta de casi iguales operandos puede causar pérdida extrema de precisión. Cuando restamos dos números casi iguales fijamos los dígitos más significativos a cero, dejandonos solo con los dígitos insignificantes y más erróneos. Por ejemplo, al determinar un derivado de una función se utiliza la siguiente fórmula:

    Q()h)=f()a+h)− − f()a)h.{displaystyle Q(h)={frac {f(a+h)-f(a)}{h}}

    Intuitivamente uno querría un h muy cerca de cero; sin embargo, al utilizar operaciones de punto flotante, el número más pequeño no dará la mejor aproximación de un derivado. As h crece más pequeño, la diferencia entre f()a + h) y f()a) crece más pequeño, cancelando los dígitos más significativos y menos erróneos y haciendo los dígitos más erróneos más importantes. Como resultado, el menor número de h posible dará una aproximación más errónea de un derivado que un número algo mayor. Este es quizás el problema de precisión más común y serio.
  • Las conversiones al entero no son intuitivas: la conversión (63.0/9.0) a los rendimientos enteros 7, pero la conversión (0.63/0.09) puede producir 6. Esto se debe a que las conversiones generalmente truncate en lugar de redondo. Las funciones de piso y techo pueden producir respuestas que están fuera por uno del valor esperado intuitivamente.
  • Rango de exponentes limitados: los resultados pueden desbordar el rendimiento de la infinidad, o la subfluencia que produce un número subnormal o cero. En estos casos se perderá la precisión.
  • La prueba para una división segura es problemática: Verificar que el divisor no es cero no garantiza que una división no se desborde.
  • La prueba de la igualdad es problemática. Dos secuencias computacionales que son matemáticamente iguales pueden producir diferentes valores de punto flotante.

Incidentes

Precisión de máquina y análisis de errores hacia atrás

La precisión de la máquina es una cantidad que caracteriza la precisión de un sistema de punto flotante y se utiliza en el análisis de error hacia atrás de los algoritmos de punto flotante. También se conoce como redondeo de unidades o épsilon de máquina. Normalmente se denota Εmach, su valor depende del redondeo particular que se utilice.

Con redondeo a cero,

Emach=B1− − P,{displaystyle mathrm ¿Qué?
Emach=12B1− − P,{displaystyle mathrm {E}{text{mach}={tfrac} {1}}B^{1-P}
BPB

Esto es importante ya que limita el error relativo al representar cualquier número real distinto de cero x dentro del rango normalizado de un sistema de punto flotante:

Silenciofl⁡ ⁡ ()x)− − xxSilencio≤ ≤ Emach.{displaystyle left WordPress{frac {fl} (x)-x}right WordPressleq mathrm {E} _{text{mach}}}

El análisis de error hacia atrás, cuya teoría fue desarrollada y popularizada por James H. Wilkinson, se puede utilizar para establecer que un algoritmo que implementa una función numérica es numéricamente estable. El enfoque básico es mostrar que aunque el resultado calculado, debido a errores de redondeo, no será exactamente correcto, es la solución exacta a un problema cercano con datos de entrada ligeramente perturbados. Si la perturbación requerida es pequeña, del orden de la incertidumbre en los datos de entrada, entonces los resultados son, en cierto sentido, tan precisos como los datos 'se merecen'. El algoritmo se define entonces como estable hacia atrás. La estabilidad es una medida de la sensibilidad a los errores de redondeo de un procedimiento numérico dado; por el contrario, el número de condición de una función para un problema dado indica la sensibilidad inherente de la función a pequeñas perturbaciones en su entrada y es independiente de la implementación utilizada para resolver el problema.

Como ejemplo trivial, considere una simple expresión dando el producto interior de (longitud dos) vectores x{displaystyle x} y Sí.{displaystyle y}, entonces

fl⁡ ⁡ ()x⋅ ⋅ Sí.)=fl⁡ ⁡ ()fl()x1⋅ ⋅ Sí.1)+fl⁡ ⁡ ()x2⋅ ⋅ Sí.2)),Dondefl⁡ ⁡ ())indica correctamente aritmética de punto flotante redondeado=fl⁡ ⁡ ()()x1⋅ ⋅ Sí.1)()1+δ δ 1)+()x2⋅ ⋅ Sí.2)()1+δ δ 2)),Dondeδ δ n≤ ≤ Emach,desde arriba=()()x1⋅ ⋅ Sí.1)()1+δ δ 1)+()x2⋅ ⋅ Sí.2)()1+δ δ 2))()1+δ δ 3)=()x1⋅ ⋅ Sí.1)()1+δ δ 1)()1+δ δ 3)+()x2⋅ ⋅ Sí.2)()1+δ δ 2)()1+δ δ 3),################################################################################################################################################################################################################################################################ _{n}leq mathrm {fnMicrosoft Sans Serif} {fnMicrosoft Sans Serif} {fnMicrosoft Sans Serif})(1+delta _{1})+(x_{2}cdot y_{2})(1+delta _{2}) {c}} {ccd]} {0dd] _{1})(1+delta _{3})+(x_{2}cdot y_{2})(1+delta _{2})(1+delta _{3}),end{aligned}}}
fl⁡ ⁡ ()x⋅ ⋅ Sí.)=x^ ^ ⋅ ⋅ Sí.^ ^ ,{displaystyle operatorname {fl} (xcdot y)={hat {x}cdot {hat {y}}}}

dónde

x^ ^ 1=x1()1+δ δ 1);x^ ^ 2=x2()1+δ δ 2);Sí.^ ^ 1=Sí.1()1+δ δ 3);Sí.^ ^ 2=Sí.2()1+δ δ 3),{displaystyle {begin{aligned}{hat {x}_{1}=x_{1}(1+delta _{1}); {x}_{2}=x_{2}(1+delta _{2});{hat {y}_{1} {1+delta} _{3}); {y}_{2} {y_{2}(1+delta _{3}end{aligned}}}

dónde

δ δ n≤ ≤ Emach{displaystyle delta _{n}leq mathrm {E} {text{mach}}

por definición, que es la suma de dos datos de entrada ligeramente perturbados (del orden de Εmach), por lo que es estable hacia atrás. Para ejemplos más realistas en álgebra lineal numérica, consulte Higham 2002 y otras referencias a continuación.

Minimizar el efecto de los problemas de precisión

Aunque se garantiza que las operaciones aritméticas individuales de IEEE 754 son precisas dentro de la mitad de un ULP, las fórmulas más complicadas pueden sufrir errores mayores por una variedad de razones. La pérdida de precisión puede ser sustancial si un problema o sus datos están mal acondicionados, lo que significa que el resultado correcto es hipersensible a pequeñas perturbaciones en sus datos. Sin embargo, incluso las funciones que están bien condicionadas pueden sufrir una gran pérdida de precisión si se utiliza un algoritmo numéricamente inestable para esos datos: formulaciones de expresiones aparentemente equivalentes en un lenguaje de programación pueden diferir notablemente en su estabilidad numérica. Un enfoque para eliminar el riesgo de tal pérdida de precisión es el diseño y análisis de algoritmos numéricamente estables, que es un objetivo de la rama de las matemáticas conocida como análisis numérico. Otro enfoque que puede proteger contra el riesgo de inestabilidades numéricas es el cálculo de valores intermedios (scratch) en un algoritmo con una precisión mayor que la que requiere el resultado final, lo que puede eliminar, o reducir en órdenes de magnitud, dicho riesgo: IEEE 754 cuádruple La precisión y la precisión extendida están diseñadas para este propósito cuando se calcula con doble precisión.

Por ejemplo, el siguiente algoritmo es una implementación directa para calcular la función A(x) = (x−1) / (exp(x−1) − 1) que está bien condicionado en 1.0, sin embargo, se puede demostrar que es numéricamente inestable y pierde hasta la mitad de los dígitos significativos que lleva la aritmética cuando se calcula cerca de 1.0.

doble A()doble X){} doble Y, Z; // [1] Y = X - 1.0; Z = exp()Y); si ()Z ! 1.0) Z = Y / ()Z - 1.0); // [2] retorno Z;}

Sin embargo, si todos los cálculos intermedios se realizan con precisión extendida (p. ej., configurando la línea [1] en C99 long double), entonces se puede mantener la máxima precisión en el resultado final del doble. Alternativamente, un análisis numérico del algoritmo revela que si se realiza el siguiente cambio no obvio en la línea [2]:

Z = log()Z) / ()Z - 1.0);

entonces el algoritmo se vuelve numéricamente estable y puede calcular con el doble de precisión.

Para mantener las propiedades de tales programas numéricamente estables cuidadosamente construidos, se requiere un manejo cuidadoso por parte del compilador. Ciertas "optimizaciones" que los compiladores pueden hacer (por ejemplo, operaciones de reordenación) pueden ir en contra de los objetivos del software de buen comportamiento. Existe cierta controversia sobre las fallas de los compiladores y los diseños de lenguaje en esta área: C99 es un ejemplo de un lenguaje en el que dichas optimizaciones se especifican cuidadosamente para mantener la precisión numérica. Consulte las referencias externas al final de este artículo.

Un tratamiento detallado de las técnicas para escribir software de punto flotante de alta calidad está más allá del alcance de este artículo, y se hace referencia al lector y a las demás referencias al final de este artículo. Kahan sugiere varias reglas generales que pueden disminuir sustancialmente en órdenes de magnitud el riesgo de anomalías numéricas, además de, o en lugar de, un análisis numérico más cuidadoso. Estos incluyen: como se indicó anteriormente, calcular todas las expresiones y resultados intermedios con la precisión más alta admitida en el hardware (una regla general común es tener el doble de precisión del resultado deseado, es decir, calcular con precisión doble para un resultado final de precisión simple, o en precisión doble extendida o cuádruple para resultados de hasta doble precisión); y redondear los datos de entrada y los resultados solo a la precisión requerida y respaldada por los datos de entrada (llevar un exceso de precisión en el resultado final más allá de lo requerido y respaldado por los datos de entrada puede ser engañoso, aumenta el costo de almacenamiento y disminuye la velocidad, y el exceso de bits puede afectan la convergencia de los procedimientos numéricos: en particular, la primera forma del ejemplo iterativo dado a continuación converge correctamente cuando se usa esta regla empírica). A continuación se describen brevemente varios temas y técnicas adicionales.

Como las fracciones decimales a menudo no se pueden representar exactamente en coma flotante binaria, esta aritmética es óptima cuando simplemente se usa para medir cantidades del mundo real en una amplia gama de escalas (como el período orbital de un luna alrededor de Saturno o la masa de un protón), y en el peor de los casos cuando se espera modelar las interacciones de cantidades expresadas como cadenas decimales que se espera que sean exactas. Un ejemplo de este último caso son los cálculos financieros. Por esta razón, el software financiero tiende a no utilizar una representación binaria de números de punto flotante. El "decimal" El tipo de datos de los lenguajes de programación C# y Python, y los formatos decimales del estándar IEEE 754-2008, están diseñados para evitar los problemas de las representaciones binarias de punto flotante cuando se aplican a valores decimales exactos ingresados por humanos, y hacer que la aritmética siempre se comporte como se esperaba cuando los números se imprimen en decimal.

Las expectativas de las matemáticas no pueden realizarse en el campo de la computación de punto flotante. Por ejemplo, se sabe que ()x+Sí.)()x− − Sí.)=x2− − Sí.2{displaystyle (x+y)(x-y)=x^{2}-y^{2},}, y eso pecado2⁡ ⁡ Silencio Silencio +#2⁡ ⁡ Silencio Silencio =1{displaystyle sin ^{2}{theta }+cos ^{2}{theta }=1,}, sin embargo estos hechos no pueden basarse en cuando las cantidades involucradas son el resultado de la computación de punto flotante.

El uso de la prueba de igualdad (if (x==y)...) requiere cuidado cuando se trata de números de punto flotante. Incluso expresiones simples como 0.6/0.2-3==0, en la mayoría de las computadoras, no serán verdaderas (en IEEE 754 de doble precisión, por ejemplo, 0.6/0.2 - 3 es aproximadamente igual a -4.44089209850063e-16). En consecuencia, estas pruebas a veces se reemplazan con "fuzzy" comparaciones (if (abs(x-y) < epsilon)..., donde epsilon es lo suficientemente pequeño y adaptado a la aplicación, como 1.0E−13). La sabiduría de hacer esto varía mucho y puede requerir un análisis numérico para enlazar épsilon. Los valores derivados de la representación de datos primarios y sus comparaciones deben realizarse con una precisión más amplia y extendida para minimizar el riesgo de tales inconsistencias debido a errores de redondeo. A menudo es mejor organizar el código de tal manera que dichas pruebas sean innecesarias. Por ejemplo, en geometría computacional, las pruebas exactas de si un punto se encuentra fuera o dentro de una línea o un plano definido por otros puntos se pueden realizar utilizando precisión adaptativa o métodos aritméticos exactos.

Los pequeños errores en la aritmética de punto flotante pueden aumentar cuando los algoritmos matemáticos realizan operaciones una enorme cantidad de veces. Algunos ejemplos son la inversión de matrices, el cálculo de vectores propios y la resolución de ecuaciones diferenciales. Estos algoritmos deben diseñarse con mucho cuidado, utilizando enfoques numéricos como el refinamiento iterativo, para que funcionen bien.

La suma de un vector de valores de punto flotante es un algoritmo básico en la computación científica, por lo que es esencial saber cuándo puede ocurrir una pérdida de importancia. Por ejemplo, si uno está sumando una gran cantidad de números, los sumandos individuales son muy pequeños en comparación con la suma. Esto puede conducir a la pérdida de importancia. Una adición típica sería algo así como

3253.671
+ 3.141276
---------
3256.812

Los 3 dígitos bajos de los sumandos se pierden efectivamente. Supongamos, por ejemplo, que uno necesita sumar muchos números, todos aproximadamente iguales a 3. Después de haber sumado 1000 de ellos, la suma acumulada es aproximadamente 3000; los dígitos perdidos no se recuperan. El algoritmo de suma de Kahan se puede utilizar para reducir los errores.

El error de redondeo puede afectar la convergencia y la precisión de los procedimientos numéricos iterativos. Como ejemplo, Arquímedes aproximó π calculando los perímetros de los polígonos que inscriben y circunscriben un círculo, comenzando con hexágonos y duplicando sucesivamente el número de lados. Como se señaló anteriormente, los cálculos se pueden reorganizar de una manera matemáticamente equivalente pero menos propensa a errores (análisis numérico). Dos formas de la fórmula de recurrencia para el polígono circunscrito son:

Aquí hay un cálculo usando IEEE "doble" (un significado con 53 bits de precisión) aritmética:

 i 6 × 2i ×i, primera forma 6 × 2i ×i, segunda forma
-----
0 3.4641016151377543863 3.4641016151377543863
1 3.2153903091734710173 3.2153903091734723496
2 3.1596599420974940120 3.1596599420975006733
3 3.1460862151314012979 3.1460862151314352708
4 3.1427145996453136334 3.1427145996453689225
5 3.1418730499801259536 3.1418730499798241950
6 3.1416627470548084133 3.1416627470568494473
7 3.1416101765997805905 3.1416101766046906629
8 3.1415970343230776862 3.1415970343215275928
9 3.1415937488171150615 3.1415937487713536668
10 3.1415929278733740748 3.1415929273850979885
11 3.1415927256228504127 3.1415927220386148377
12 3.1415926717412858693 3.1415926707019992125
13 3.14159261890114560 3.1415926578678454728
14 3.1415926717412858693 3.1415926546593073709
15 3.1415919358822321783 3.1415926538571730119
16 3.1415926717412858693 3.1415926536566394222
17 3.1415810075796233302 3.1415926536065061913
18 3.1415926717412858693 3.1415926535939728836
19 3.1414061547378810956 3.14159265359083901
20 3.1405434924008406305 3.1415926535900560168
21 3.1400068646912273617 3.1415926535898608396
22 3.1349453756585929919 3.1415926535898122118
23 3.1400068646912273617 3.1415926535897995552
24 3.2245152435345525443 3.1415926535897968907
25 3.1415926535897962246
26 3.1415926535897962246
27 3.1415926535897962246
28 3.1415926535897962246
El verdadero valor es 3.14159265358979323846264338327...

Si bien las dos formas de la fórmula de recurrencia son matemáticamente equivalentes, la primera resta 1 de un número extremadamente cercano a 1, lo que genera una pérdida cada vez más problemática de dígitos significativos. A medida que la recurrencia se aplica repetidamente, la precisión mejora al principio, pero luego se deteriora. Nunca supera los 8 dígitos, aunque la aritmética de 53 bits debería tener una precisión de 16 dígitos. Cuando se usa la segunda forma de recurrencia, el valor converge a 15 dígitos de precisión.

"Matemáticas rápidas" optimización

La mencionada falta de asociatividad de las operaciones de coma flotante en general significa que los compiladores no pueden reordenar las expresiones aritméticas con tanta eficacia como lo harían con la aritmética de enteros y de coma fija, lo que presenta un obstáculo en las optimizaciones, como la eliminación de subexpresiones comunes y la vectorización automática. Las "matemáticas rápidas" La opción en muchos compiladores (ICC, GCC, Clang, MSVC...) activa la reasociación junto con suposiciones inseguras como la falta de NaN y números infinitos en IEEE 754. Algunos compiladores también ofrecen opciones más granulares para activar solo la reasociación. En cualquier caso, el programador está expuesto a muchos de los errores de precisión mencionados anteriormente para la parte del programa que usa "rápido" Matemáticas.

En algunos compiladores (GCC y Clang), activar "rápido" math puede hacer que el programa deshabilite los valores flotantes subnormales al inicio, lo que afecta el comportamiento de punto flotante no solo del código generado, sino también de cualquier programa que use dicho código como una biblioteca.

En la mayoría de los compiladores de Fortran, según lo permite el estándar de Fortran ISO/IEC 1539-1:2004, la reasociación es la opción predeterminada, y las interrupciones se evitan en gran medida mediante la función "protect parens" (también activado de forma predeterminada). Esta configuración evita que el compilador se vuelva a asociar más allá de los límites de los paréntesis. Intel Fortran Compiler es un caso atípico notable.

Un problema común en "rápido" La matemática es que las subexpresiones pueden no optimizarse de manera idéntica de un lugar a otro, lo que genera diferencias inesperadas. Una interpretación del problema es que "rápido" Las matemáticas implementadas actualmente tienen una semántica pobremente definida. Un intento de formalizar "rápido" Las optimizaciones matemáticas se ven en Icing, un compilador verificado.