Aritmética de punto fijo

Formato informático para representar números reales

En informática , el punto fijo es un método para representar números fraccionarios (no enteros) mediante el almacenamiento de un número fijo de dígitos de su parte fraccionaria. Las cantidades en dólares , por ejemplo, a menudo se almacenan con exactamente dos dígitos fraccionarios, que representan los centavos (1/100 de dólar). De manera más general, el término puede referirse a la representación de valores fraccionarios como múltiplos enteros de alguna unidad pequeña fija, por ejemplo, una cantidad fraccionaria de horas como un múltiplo entero de intervalos de diez minutos. La representación de números en punto fijo a menudo se contrasta con la representación en punto flotante, más complicada y computacionalmente exigente .

En la representación de punto fijo, la fracción se expresa a menudo en la misma base numérica que la parte entera, pero utilizando potencias negativas de la base b . Las variantes más comunes son decimal (base 10) y binaria (base 2). Esta última también se conoce comúnmente como escala binaria . Por lo tanto, si se almacenan n dígitos de fracción, el valor siempre será un múltiplo entero de b n . La representación de punto fijo también se puede utilizar para omitir los dígitos de orden inferior de los valores enteros, por ejemplo, al representar grandes valores en dólares como múltiplos de $1000.

Cuando se muestran números decimales de punto fijo para lectura humana, los dígitos fraccionarios suelen estar separados de los de la parte entera por un carácter de base (normalmente "." en inglés, pero "," o algún otro símbolo en muchos otros idiomas). Sin embargo, internamente no hay separación, y la distinción entre los dos grupos de dígitos está definida únicamente por los programas que manejan dichos números.

La representación en punto fijo era la norma en las calculadoras mecánicas . Dado que la mayoría de los procesadores modernos tienen una unidad de punto flotante (FPU) rápida, las representaciones en punto fijo en las implementaciones basadas en procesadores ahora se usan solo en situaciones especiales, como en microprocesadores y microcontroladores integrados de bajo costo ; en aplicaciones que exigen alta velocidad o bajo consumo de energía o área de chip pequeña , como procesamiento de imágenes , video y señales digitales ; o cuando su uso es más natural para el problema. Ejemplos de esto último son la contabilidad de cantidades en dólares, cuando las fracciones de centavos deben redondearse a centavos enteros de formas estrictamente prescritas; y la evaluación de funciones por búsqueda en tabla , o cualquier aplicación donde los números racionales deben representarse sin errores de redondeo (lo que hace el punto fijo pero no el punto flotante). La representación en punto fijo sigue siendo la norma para las implementaciones de matriz de puertas programables en campo (FPGA), ya que el soporte de punto flotante en un FPGA requiere significativamente más recursos que el soporte de punto fijo. [1]

Representación

Representación de punto fijocon escala 1/100
Valor
representado

Representación interna
0.000
0,550
0,9999
2200
-14,1−1410
314.16031416

Una representación de punto fijo de un número fraccionario es esencialmente un entero que se multiplicará implícitamente por un factor de escala fijo. Por ejemplo, el valor 1,23 se puede almacenar en una variable como el valor entero 1230 con un factor de escala implícito de 1/1000 (lo que significa que se supone implícitamente que los últimos 3 dígitos decimales son una fracción decimal), y el valor 1 230 000 se puede representar como 1230 con un factor de escala implícito de 1000 (con "menos 3" dígitos decimales fraccionarios implícitos, es decir, con 3 dígitos cero implícitos a la derecha). Esta representación permite que las unidades lógicas aritméticas de enteros estándar realicen cálculos con números racionales .

Los valores negativos se representan generalmente en formato binario de punto fijo como un entero con signo en representación de complemento a dos con un factor de escala implícito como el anterior. El signo del valor siempre se indicará mediante el primer bit almacenado (1 = negativo, 0 = no negativo), incluso si el número de bits fraccionarios es mayor o igual que el número total de bits. Por ejemplo, el entero binario con signo de 8 bits (11110101) 2 = −11, tomado con -3, +5 y +12 bits fraccionarios implícitos, representaría los valores −11/2 −3 = −88, −11/2 5 = −0. 343 75 y −11/2 12 = −0. 002 685 546 875 , respectivamente.

Alternativamente, los valores negativos pueden representarse mediante un entero en el formato de signo-magnitud , en cuyo caso el signo nunca se incluye en el número de bits fraccionarios implícitos. Esta variante se utiliza más comúnmente en la aritmética decimal de punto fijo. Por lo tanto, el entero decimal con signo de 5 dígitos (−00025) 10 , tomado con -3, +5 y +12 dígitos fraccionarios decimales implícitos, representaría los valores −25/10 −3 = −25000, −25/10 5 = −0,00025 y −25/10 12 = −0, 000 000 000 025 , respectivamente.

Un programa normalmente supondrá que todos los valores de punto fijo que se almacenarán en una variable dada, o que se producirán mediante una instrucción dada , tendrán el mismo factor de escala. Este parámetro normalmente puede ser elegido por el programador dependiendo de la precisión necesaria y del rango de valores que se almacenarán.

Es posible que el factor de escala de una variable o fórmula no aparezca explícitamente en el programa. En ese caso, las buenas prácticas de programación exigen que se proporcione en la documentación , al menos como comentario en el código fuente .

Elección de factores de escala

Para una mayor eficiencia, los factores de escala se eligen a menudo como potencias (positivas o negativas) de la base b utilizada para representar los números enteros internamente. Sin embargo, a menudo el mejor factor de escala viene determinado por la aplicación. Por lo tanto, a menudo se utilizan factores de escala que son potencias de 10 (por ejemplo, 1/100 para valores en dólares), para conveniencia humana, incluso cuando los números enteros se representan internamente en binario. Los factores de escala decimales también encajan bien con el sistema métrico (SI) , ya que la elección del factor de escala de punto fijo a menudo es equivalente a la elección de una unidad de medida (como centímetros o micrones en lugar de metros ).

Sin embargo, ocasionalmente se pueden utilizar otros factores de escala, por ejemplo, una cantidad fraccionaria de horas se puede representar como un número entero de segundos, es decir, como un número de punto fijo con un factor de escala de 1/3600.

Incluso con el redondeo más cuidadoso, los valores de punto fijo representados con un factor de escala S pueden tener un error de hasta ±0,5 en el entero almacenado, es decir, ±0,5 S en el valor. Por lo tanto, los factores de escala más pequeños generalmente producen resultados más precisos.

Por otra parte, un factor de escala más pequeño significa un rango más pequeño de los valores que se pueden almacenar en una variable de programa dada. El valor máximo de punto fijo que se puede almacenar en una variable es el valor entero más grande que se puede almacenar en ella, multiplicado por el factor de escala; y lo mismo para el valor mínimo. Por ejemplo, la tabla siguiente proporciona el factor de escala implícito S , los valores mínimos y máximos representables V min y V max , y la precisión δ = S /2 de los valores que se podrían representar en formato binario de punto fijo con signo de 16 bits, dependiendo del número f de bits fraccionarios implícitos.

Parámetros de algunos formatos binarios de punto fijo con signo de 16 bits
FSdelV mín.Vmáx .
-31/2 −3 = 84262 144+ 262 136
01/2 0 = 10,532 768+ 32 767
51/2 5 = 1/32< 0,016−1024. 000 00+1023.968 75
141/2 14 = 1/ 16 384< 0. 000 031−2. 000 000 000 000 00+1.999 938 964 843 75
151/2 15 = 1/32 768< 0. 000 016−1. 000 000 000 000 000+0.999 969 482 421 875
161/2 16 = 1/ 65 536< 0. 000 008−0,500 000 000 000 000 0+0. 499 984 741 210 937 5
201/2 20 = 1/ 1 048 576< 0. 000 000 5−0. 031 250 000 000 000 000 00+0. 031 249 046 325 683 593 75

Se ha dicho que los formatos de punto fijo con factores de escala de la forma 2 n -1 (es decir, 1, 3, 7, 15, 31, etc.) son apropiados para el procesamiento de imágenes y otras tareas de procesamiento de señales digitales. Se supone que proporcionan conversiones más consistentes entre valores de punto fijo y flotante que el escalado 2 n habitual. El lenguaje de programación Julia implementa ambas versiones. [2]

Valores exactos

Cualquier fracción binaria a /2 m , como 1/16 o 17/32, se puede representar exactamente en coma fija, con un factor de escala de potencia de dos 1/2 n con cualquier nm . Sin embargo, la mayoría de las fracciones decimales como 0,1 o 0,123 son fracciones repetidas infinitas en base 2 y, por lo tanto, no se pueden representar de esa manera.

De manera similar, cualquier fracción decimal a /10 m , como 1/100 o 37/1000, se puede representar exactamente en punto fijo con un factor de escala de potencia de diez 1/10 n con cualquier nm . Este formato decimal también puede representar cualquier fracción binaria a /2 m , como 1/8 (0,125) o 17/32 (0,53125).

De manera más general, un número racional a / b , con a y b relativamente primos y b positivo, puede representarse exactamente en punto fijo binario sólo si b es una potencia de 2; y en punto fijo decimal sólo si b no tiene factores primos distintos de 2 y/o 5.

Comparación con punto flotante

Los cálculos de punto fijo pueden ser más rápidos y/o utilizar menos hardware que los de punto flotante. Si el rango de los valores a representar se conoce de antemano y es suficientemente limitado, el punto fijo puede hacer un mejor uso de los bits disponibles. Por ejemplo, si hay 32 bits disponibles para representar un número entre 0 y 1, una representación de punto fijo puede tener un error menor que 1,2 × 10 −10 , mientras que la representación de punto flotante estándar puede tener un error de hasta 596 × 10 −10 , porque 9 de los bits se desperdician con el signo y exponente del factor de escala dinámico. Específicamente, al comparar audio de punto fijo de 32 bits con audio de punto flotante , una grabación que requiere menos de 40 dB de margen dinámico tiene una relación señal-ruido más alta utilizando 32 bits fijos.

Los programas que utilizan cálculos de punto fijo suelen ser más portables que los que utilizan punto flotante, ya que no dependen de la disponibilidad de una FPU. Esta ventaja era particularmente fuerte antes de que se adoptara ampliamente el estándar IEEE de punto flotante , cuando los cálculos de punto flotante con los mismos datos arrojaban resultados diferentes según el fabricante y, a menudo, según el modelo de computadora.

Muchos procesadores integrados carecen de una FPU, porque las unidades aritméticas de números enteros requieren sustancialmente menos puertas lógicas y consumen un área de chip mucho menor que una FPU; y la emulación de software de punto flotante en dispositivos de baja velocidad sería demasiado lenta para la mayoría de las aplicaciones. Los chips de CPU para las primeras computadoras personales y consolas de juegos , como Intel 386 y 486SX , también carecían de una FPU.

La resolución absoluta (diferencia entre valores sucesivos) de cualquier formato de punto fijo es constante en todo el rango, es decir, el factor de escala S . Por el contrario, la resolución relativa de un formato de punto flotante es aproximadamente constante en todo su rango, variando dentro de un factor de la base b ; mientras que su resolución absoluta varía en muchos órdenes de magnitud, como los valores mismos.

En muchos casos, los errores de redondeo y truncamiento de los cálculos de punto fijo son más fáciles de analizar que los de los cálculos de punto flotante equivalentes. La aplicación de técnicas de linealización al truncamiento, como el tramado y/o la modelación de ruido, es más sencilla dentro de la aritmética de punto fijo. Por otro lado, el uso del punto fijo requiere un mayor cuidado por parte del programador. Evitar el desbordamiento requiere estimaciones mucho más estrictas para los rangos de variables y todos los valores intermedios en el cálculo, y a menudo también código adicional para ajustar sus factores de escala. La programación de punto fijo normalmente requiere el uso de tipos enteros de diferentes anchos . Las aplicaciones de punto fijo pueden hacer uso del punto flotante de bloque , que es un entorno de punto fijo en el que cada matriz (bloque) de datos de punto fijo se escala con un exponente común en una sola palabra.

Aplicaciones

Un uso común del punto fijo decimal es el almacenamiento de valores monetarios, para los cuales las complicadas reglas de redondeo de los números de punto flotante suelen ser un inconveniente. Por ejemplo, la aplicación de gestión de dinero de código abierto GnuCash , escrita en C, cambió del punto flotante al punto fijo a partir de la versión 1.6 por este motivo.

El punto fijo binario (escalamiento binario) se utilizó ampliamente desde finales de la década de 1960 hasta la década de 1980 para cálculos en tiempo real que requerían un uso intensivo de las matemáticas, como la simulación de vuelo y los algoritmos de control de plantas de energía nuclear . Todavía se utiliza en muchas aplicaciones DSP y microprocesadores personalizados. Los cálculos que involucran ángulos utilizarían la medición angular binaria .

El punto fijo binario se utiliza en los coprocesadores CORDIC de la serie STM32G4 y en los algoritmos de transformada de coseno discreta utilizados para comprimir imágenes JPEG .

Los instrumentos electrónicos, como los medidores de electricidad y los relojes digitales, a menudo utilizan polinomios para compensar los errores introducidos, por ejemplo, los de temperatura o de voltaje de la fuente de alimentación. Los coeficientes se generan mediante regresión polinómica . Los polinomios binarios de punto fijo pueden utilizar más bits de precisión que los de punto flotante, y lo hacen en código rápido utilizando CPU económicas. La precisión, crucial para los instrumentos, se compara bien con los cálculos de punto flotante de bits equivalentes, si los polinomios de punto fijo se evalúan utilizando el método de Horner (por ejemplo, y = (( ax + b ) x + c ) x + d ) para reducir la cantidad de veces que se produce el redondeo, y las multiplicaciones de punto fijo utilizan sumandos de redondeo.

Operaciones

Suma y resta

Para sumar o restar dos valores con el mismo factor de escala implícito, es suficiente sumar o restar los enteros subyacentes; el resultado tendrá su factor de escala implícito común, por lo que puede almacenarse en las mismas variables de programa que los operandos. Estas operaciones producen el resultado matemático exacto, siempre que no se produzca un desbordamiento , es decir, siempre que el entero resultante pueda almacenarse en la variable de programa receptora . Si los operandos tienen diferentes factores de escala, deben convertirse a un factor de escala común antes de la operación.

Multiplicación

Para multiplicar dos números de coma fija, basta con multiplicar los dos enteros subyacentes y suponer que el factor de escala del resultado es el producto de sus factores de escala. El resultado será exacto, sin redondeo, siempre que no desborde la variable receptora.

Por ejemplo, multiplicar los números 123 escalado por 1/1000 (0,123) y 25 escalado por 1/10 (2,5) da como resultado el entero 123×25 = 3075 escalado por (1/1000)×(1/10) = 1/10000, es decir, 3075/10000 = 0,3075. Como otro ejemplo, multiplicar el primer número por 155 escalado implícitamente por 1/32 (155/32 = 4,84375) da como resultado el entero 123×155 = 19065 con factor de escala implícito (1/1000)×(1/32) = 1/32000, es decir, 19065/32000 = 0,59578125.

En binario, es común usar un factor de escala que es una potencia de dos. Después de la multiplicación, el factor de escala se puede dividir desplazándolo hacia la derecha. El desplazamiento es simple y rápido en la mayoría de las computadoras. El redondeo es posible agregando un 'sumando de redondeo' de la mitad del factor de escala antes del desplazamiento; La prueba: round(x/y) = floor(x/y + 0.5) = floor((x + y/2)/y) = shift-of-n(x + 2^(n-1)) Un método similar se puede usar en cualquier escala.

División

Para dividir dos números de punto fijo, se toma el cociente entero de sus números enteros subyacentes y se supone que el factor de escala es el cociente de sus factores de escala. En general, la primera división requiere redondeo y, por lo tanto, el resultado no es exacto.

Por ejemplo, la división de 3456 escalado por 1/100 (34,56) y 1234 escalado por 1/1000 (1,234) produce el entero 3456÷1234 = 3 (redondeado) con factor de escala (1/100)/(1/1000) = 10, es decir, 30. Como otro ejemplo, la división del primer número por 155 escalado implícitamente por 1/32 (155/32 = 4,84375) produce el entero 3456÷155 = 22 (redondeado) con factor de escala implícito (1/100)/(1/32) = 32/100 = 8/25, es decir, 22×32/100 = 7,04.

Si el resultado no es exacto, el error introducido por el redondeo se puede reducir o incluso eliminar convirtiendo el dividendo a un factor de escala menor. Por ejemplo, si r = 1,23 se representa como 123 con escala 1/100, y s = 6,25 se representa como 6250 con escala 1/1000, entonces la división simple de los números enteros da como resultado 123÷6250 = 0 (redondeado) con factor de escala (1/100)/(1/1000) = 10. Si r se convierte primero a 1.230.000 con factor de escala 1/1000000, el resultado será 1.230.000÷6250 = 197 (redondeado) con factor de escala 1/1000 (0,197). El valor exacto 1,23/6,25 es 0,1968.

Conversión de escala

En la computación de punto fijo, a menudo es necesario convertir un valor a un factor de escala diferente. Esta operación es necesaria, por ejemplo:

  • Para almacenar un valor en una variable de programa que tiene un factor de escala implícito diferente;
  • Para convertir dos valores al mismo factor de escala, de modo que puedan sumarse o restarse;
  • Para restaurar el factor de escala original de un valor después de multiplicarlo o dividirlo por otro;
  • Para mejorar la precisión del resultado de una división;
  • Para garantizar que el factor de escala de un producto o cociente sea una potencia simple como 10 n o 2 n ;
  • Para garantizar que el resultado de una operación pueda almacenarse en una variable de programa sin desbordamiento;
  • Para reducir el costo del hardware que procesa datos de punto fijo.

Para convertir un número de un tipo de punto fijo con factor de escala R a otro tipo con factor de escala S , el entero subyacente debe multiplicarse por la relación R / S. Así, por ejemplo, para convertir el valor 1,23 = 123/100 de factor de escala R = 1/100 a uno con factor de escala S = 1/1000, el entero 123 debe multiplicarse por (1/100)/(1/1000) = 10, obteniéndose la representación 1230/1000.

Si el factor de escala es una potencia de la base utilizada internamente para representar el número entero, para cambiar el factor de escala solo es necesario eliminar los dígitos de orden inferior del número entero o añadir dígitos cero. Sin embargo, esta operación debe conservar el signo del número. En la representación en complemento a dos, eso significa extender el bit de signo como en las operaciones de desplazamiento aritmético .

Si S no divide a R (en particular, si el nuevo factor de escala S es mayor que el R original ), es posible que haya que redondear el nuevo entero .

En particular, si r y s son variables de punto fijo con factores de escala implícitos R y S , la operación rr × s requiere multiplicar los respectivos números enteros y dividir explícitamente el resultado por S . Es posible que haya que redondear el resultado y se produzca un desbordamiento.

Por ejemplo, si el factor de escala común es 1/100, multiplicar 1,23 por 0,25 implica multiplicar 123 por 25 para obtener 3075 con un factor de escala intermedio de 1/10000. Para volver al factor de escala original 1/100, el entero 3075 debe multiplicarse por 1/100, es decir, dividirse por 100, para obtener 31 (0,31) o 30 (0,30), según la política de redondeo utilizada.

De manera similar, la operación rr / s requerirá dividir los números enteros y multiplicar explícitamente el cociente por S. Aquí también pueden producirse redondeos y/o desbordamientos.

Conversión a y desde punto flotante

Para convertir un número de punto flotante a punto fijo, se puede multiplicar por el factor de escala S y luego redondear el resultado al entero más cercano. Se debe tener cuidado para garantizar que el resultado quepa en la variable o registro de destino. Según el factor de escala y el tamaño de almacenamiento, y según los números de entrada del rango, la conversión puede no implicar ningún redondeo.

Para convertir un número de punto fijo en un número de punto flotante, se puede convertir el entero en un número de punto flotante y luego dividirlo por el factor de escala S. Esta conversión puede implicar un redondeo si el valor absoluto del entero es mayor que 2 24 (para el punto flotante IEEE de precisión simple binario) o 2 53 (para precisión doble). Se puede producir un desbordamiento o subdesbordamiento si | S | es muy grande o muy pequeño, respectivamente.

Soporte de hardware

Escalado y renormalización

Los procesadores típicos no tienen soporte específico para la aritmética de punto fijo. Sin embargo, la mayoría de las computadoras con aritmética binaria tienen instrucciones rápidas de desplazamiento de bits que pueden multiplicar o dividir un entero por cualquier potencia de 2; en particular, una instrucción de desplazamiento aritmético . Estas instrucciones se pueden utilizar para cambiar rápidamente los factores de escala que son potencias de 2, al tiempo que se conserva el signo del número.

Los primeros ordenadores, como el IBM 1620 y el Burroughs B3500, utilizaban una representación decimal codificada en binario (BCD) para los números enteros, concretamente la base 10, en la que cada dígito decimal se codificaba de forma independiente con 4 bits. Algunos procesadores, como los microcontroladores, pueden seguir utilizándola. En dichas máquinas, la conversión de los factores de escala decimal se puede realizar mediante desplazamientos de bits o mediante la manipulación de direcciones de memoria.

Algunas arquitecturas DSP ofrecen soporte nativo para formatos de punto fijo específicos, por ejemplo, números de n bits con signo y n −1 bits fraccionarios (cuyos valores pueden variar entre −1 y casi +1). El soporte puede incluir una instrucción de multiplicación que incluye renormalización, la conversión de escala del producto de 2 n −2 a n −1 bits fraccionarios. [ cita requerida ] Si la CPU no proporciona esa característica, el programador debe guardar el producto en un registro o variable temporal lo suficientemente grande y codificar la renormalización explícitamente.

Rebosar

El desbordamiento se produce cuando el resultado de una operación aritmética es demasiado grande para almacenarse en el área de destino designada. En la suma y la resta, el resultado puede requerir un bit más que los operandos. En la multiplicación de dos enteros sin signo con m y n bits, el resultado puede tener m + n bits.

En caso de desbordamiento, los bits de orden superior suelen perderse, ya que el entero no escalado se reduce en módulo 2 n, donde n es el tamaño del área de almacenamiento. En particular, se pierde el bit de signo, lo que puede cambiar radicalmente el signo y la magnitud del valor.

Algunos procesadores pueden establecer un indicador de desbordamiento de hardware y/o generar una excepción en caso de que se produzca un desbordamiento. Algunos procesadores pueden, en cambio, proporcionar aritmética de saturación : si el resultado de una suma o resta se desbordara, almacenan en su lugar el valor con la mayor magnitud que pueda caber en el área de recepción y que tenga el signo correcto. [ cita requerida ]

Sin embargo, estas características no son muy útiles en la práctica; generalmente es más fácil y seguro seleccionar factores de escala y tamaños de palabra para excluir la posibilidad de desbordamiento, o verificar si los operandos tienen valores excesivos antes de ejecutar la operación.

Soporte de lenguaje informático

Algunos lenguajes informáticos, en particular PL/I , COBOL , Ada , JOVIAL y Coral 66 , ofrecen compatibilidad explícita con números de punto fijo. Estos proporcionan tipos de datos de punto fijo con un factor de escala binario o decimal. El compilador genera automáticamente código para realizar las conversiones de escala adecuadas al realizar operaciones con estos tipos de datos, al leer o escribir variables o al convertir los valores a otros tipos de datos, como punto flotante.

La mayoría de esos lenguajes fueron diseñados entre 1955 y 1990. Los lenguajes más modernos por lo general no ofrecen ningún tipo de datos de punto fijo o soporte para la conversión de factores de escala. Ese también es el caso de varios lenguajes más antiguos que todavía son muy populares, como FORTRAN , C y C++ . La amplia disponibilidad de procesadores rápidos de punto flotante, con un comportamiento estrictamente estandarizado, ha reducido en gran medida la demanda de soporte de punto fijo binario. [ cita requerida ] De manera similar, el soporte para punto flotante decimal en algunos lenguajes de programación, como C# y Python , ha eliminado la mayor parte de la necesidad de soporte de punto fijo decimal. En las pocas situaciones que requieren operaciones de punto fijo, el programador puede implementarlas, con conversión de escala explícita, en cualquier lenguaje de programación.

Por otra parte, todas las bases de datos relacionales y la notación SQL admiten la aritmética decimal de punto fijo y el almacenamiento de números. PostgreSQL tiene una notación especial .numéricoTipo para el almacenamiento exacto de números con hasta 1000 dígitos. [3]

Además, en 2008 la Organización Internacional de Normalización (ISO) emitió una propuesta para ampliar el lenguaje de programación C con tipos de datos de punto fijo, para el beneficio de los programas que se ejecutan en procesadores integrados. [4] Además, la Colección de compiladores GNU (GCC) tiene soporte de back-end para punto fijo. [5] [6]

Ejemplos detallados

Multiplicación de punto fijo decimal

Supongamos que existe la siguiente multiplicación con 2 números con punto fijo y 3 decimales.

( 10.500 ) ( 1.050 ) = 1 × 10.500 + 0,050 × 10.500 = 10.500 + 0,525000 = 11.025000 {\displaystyle {\begin{aligned}(10.500)(1.050)&=1\times 10.500+0.050\times 10.500\\&=10.500+0.525000=11.025000\end{aligned}}}

Observe cómo, dado que hay 3 decimales, mostramos los ceros finales. Para volver a caracterizar esto como una multiplicación de números enteros, primero debemos multiplicar moviendo todos los decimales a números enteros, luego multiplicaremos por para volver a ponerlos. La ecuación ahora se ve así 1000   ( = 10 3 ) {\displaystyle 1000\ (=10^{3})} 1 / 1000   ( = 10 3 ) {\displaystyle 1/1000\ (=10^{-3})}

( 10.500 ) ( 10 3 ) ( 1.050 ) ( 10 3 ) ( 10 3 ) ( 10 3 ) = ( 10500 ) ( 1050 ) ( 10 6 ) = 11 025 000 ( 10 6 ) = 11.025000 {\displaystyle {\begin{aligned}(10.500)(10^{3})(1.050)(10^{3})(10^{-3})(10^{-3})&=(10500)(1050)(10^{-6})\\&=11\,025\,000(10^{-6})\\&=11.025000\end{aligned}}}

Esto funciona de manera equivalente si elegimos una base diferente, en particular la base 2 para el cálculo, ya que un desplazamiento de bit es lo mismo que una multiplicación o división por un orden de 2. Tres dígitos decimales equivalen a unos 10 dígitos binarios, por lo que deberíamos redondear 0,05 a 10 bits después del punto binario. La aproximación más cercana es entonces 0,0000110011.

10 = 8 + 2 = 2 3 + 2 1 1 = 2 0 0,5 = 2 1 0,05 = 0,0000110011 2 {\displaystyle {\begin{aligned}10&=8+2=2^{3}+2^{1}\\1&=2^{0}\\0.5&=2^{-1}\\0.05&=0.0000110011_{2}\end{aligned}}}

Así que nuestra multiplicación se convierte en

( 1010.100 ) ( 2 3 ) ( 1.0000110011 ) ( 2 10 ) ( 2 13 ) = ( 1010100 ) ( 10000110011 ) ( 2 13 ) = ( 10110000010111100 ) ( 2 13 ) = 1011.0000010111100 {\displaystyle {\begin{aligned}(1010.100)(2^{3})(1.0000110011)(2^{10})(2^{-13})&=(1010100)(10000110011)(2^{-13})\\&=(10110000010111100)(2^{-13})\\&=1011.0000010111100\end{aligned}}}

Esto se redondea a 11,023 con tres dígitos después del punto decimal.

Multiplicación binaria de punto fijo

Consideremos la tarea de calcular el producto de 1,2 y 5,6 con punto fijo binario utilizando 16 bits fraccionarios. Para representar los dos números, se los multiplica por 2 16 , obteniendo 78 643 ,2 y 367 001 ,6; y se redondean estos valores a los enteros más cercanos, obteniendo 78 643 y 367 002 . Estos números encajarán cómodamente en una palabra de 32 bits con formato de complemento a dos con signo.

Al multiplicar estos números enteros, se obtiene el número entero de 35 bits 28 862 138 286 con 32 bits fraccionarios, sin ningún redondeo. Tenga en cuenta que almacenar este valor directamente en una variable entera de 32 bits provocaría un desbordamiento y la pérdida de los bits más significativos. En la práctica, probablemente se almacenaría en una variable entera con signo de 64 bits o en un registro .

Si el resultado se va a almacenar en el mismo formato que los datos, con 16 bits fraccionarios, ese entero se debe dividir por 2 16 , lo que da aproximadamente 440 401 .28, y luego se redondea al entero más cercano. Este efecto se puede lograr sumando 2 15 y luego desplazando el resultado por 16 bits. El resultado es 440 401 , que representa el valor 6. 719 985 961 914 062 5 . Teniendo en cuenta la precisión del formato, ese valor se expresa mejor como 6. 719 986 ± 0. 000 008 (sin contar el error que proviene de las aproximaciones de operandos). El resultado correcto sería 1.2 × 5.6 = 6.72.

Para un ejemplo más complicado, supongamos que los dos números 1.2 y 5.6 están representados en formato de punto fijo de 32 bits con 30 y 20 bits de fracción, respectivamente. Al escalar por 2 30 y 2 20 se obtienen 1 288 490 188 .8 y 5 872 025 .6, que se redondean a 1 288 490 189 y 5 872 026 , respectivamente. Ambos números todavía caben en una variable entera con signo de 32 bits y representan las fracciones.

1. 200 000 000 186 264 514 923 095 703 125 y
5.600 000 381 469 726 562 50

Su producto es (exactamente) el entero de 53 bits 7 566 047 890 552 914 , que tiene 30+20 = 50 bits de fracción implícitos y, por lo tanto, representa la fracción

6. 720 000 458 806 753 229 623 609 513 510

Si optamos por representar este valor en formato fijo de 16 bits con signo y 8 bits fraccionarios, debemos dividir el producto entero por 2 50-8 = 2 42 y redondear el resultado; lo que se puede lograr sumando 2 41 y desplazando 42 bits. El resultado es 1720, que representa el valor 1720/2 8 = 6. 718 75 , o aproximadamente 6.719 ± 0.002.

Notaciones

Se han utilizado varias notaciones para especificar de forma concisa los parámetros de un formato de punto fijo. En la siguiente lista, f representa el número de bits fraccionarios, m el número de bits de magnitud o enteros, s el número de bits de signo y b el número total de bits.

  • El lenguaje de programación COBOL admitía originalmente números decimales de precisión fija con tamaño arbitrario y escala decimal, cuyo formato se especificaba "gráficamente" con la directiva PIC . Por ejemplo, PIC S9999V99 especificaba un entero decimal de 6 dígitos con signo de magnitud y dos dígitos decimales fraccionarios. [7]
  • El constructo REAL FIXED BINARY ( p , f ) se utiliza en el lenguaje de programación PL/I para especificar un tipo de datos binarios con signo de punto fijo con p bits en total (sin incluir el signo) con f bits en la parte fraccionaria; es decir, un entero con signo de p +1 bit con un factor de escala de 1/2 f . Este último puede ser positivo o negativo. Se puede especificar COMPLEX en lugar de REAL y DECIMAL en lugar de BINARY para la base 10.
  • En el lenguaje de programación Ada , un tipo de datos numéricos se puede especificar, por ejemplo, mediante , es decir, una representación de punto fijo que consiste en un entero binario con signo en formato de complemento a dos con 7 bits fraccionarios implícitos (lo que proporciona un factor de escala de 1/128) y al menos 15 bits en total (lo que garantiza un rango real de -128,00 a casi +128,00). [8]type F is delta 0.01 range -100.0 .. 100.0
  • La notación Q fue definida por Texas Instruments . [9] Uno escribe Q f para especificar un valor binario de punto fijo con signo y f bits fraccionarios; por ejemplo, Q15 especifica un entero con signo en notación de complemento a dos con un factor de escala 1/2 15 . El código Q m . f especifica adicionalmente que el número tiene m bits en la parte entera del valor, sin contar el bit de signo. Por lo tanto, Q1.30 describiría un formato binario de punto fijo con 1 bit entero y 30 bits fraccionarios, que podrían almacenarse como un entero de complemento a 2 de 32 bits con factor de escala 1/2 30 . [9] [10] ARM ha utilizado una notación similar , excepto que cuentan el bit de signo en el valor de m ; por lo que el mismo formato anterior se especificaría como Q2.30 . [11] [12]
  • La notación B m se ha utilizado para indicar un formato binario fijo con m bits en la parte entera; el resto de la palabra son bits fraccionarios. Por ejemplo, los valores máximo y mínimo que se pueden almacenar en un número B16 con signo son ≈32767,9999847 y −32768,0, respectivamente.
  • La empresa VisSim utilizó fx m . b para denotar un valor binario de punto fijo con b bits en total y m bits en la parte entera; es decir, un entero de b bits con factor de escala 1/2 bm . Por lo tanto, fx1.16 significaría un número de 16 bits con 1 bit en la parte entera y 15 en la fracción. [13]
  • La Guía del usuario de PS2 GS ( "Sintetizador gráfico" ) utiliza la notación s : m : f , donde s especifica la presencia (0 o 1) de bit de signo. [14] Por ejemplo, 0:5:3 representa un entero de 8 bits sin signo con un factor de escala de 1/2 3 .
  • El lenguaje de programación LabVIEW utiliza la notación < s , b , m > para especificar los parámetros de un número de punto fijo 'FXP'. El componente s puede ser '+' o '±', lo que significa un número sin signo o con signo en complemento a 2, respectivamente. El componente b es el número total de bits y m es el número de bits en la parte entera.

Ejemplos de aplicaciones de software

  • El popular formato de fuente TrueType utiliza un sistema binario de punto fijo con signo de 32 bits y 26 bits a la izquierda del decimal para algunos valores numéricos en sus instrucciones. [15] Este formato fue elegido para proporcionar la cantidad mínima de precisión requerida para las sugerencias y por razones de rendimiento. [16]
  • Con la excepción de Nintendo 64 , todos los juegos 3D para la quinta generación de consolas de videojuegos , incluyendo 3DO Interactive Multiplayer , PlayStation , Saturn y Jaguar [17] utilizan aritmética de punto fijo, ya que los sistemas carecen de unidades de punto flotante de hardware. El coprocesador de transformación de PlayStation admite un formato de punto fijo de 16 bits con 12 bits fraccionarios, mientras que los coprocesadores VDP de Sega Saturn usaban un formato de punto fijo de 32 bits reservando los 16 bits inferiores para la parte fraccionaria.
  • El software de composición tipográfica TeX , ampliamente utilizado por científicos y matemáticos, utiliza números binarios de punto fijo con signo de 32 bits y 16 bits fraccionarios para todos los cálculos de posición. Los valores se interpretan como fracciones de un punto de tipógrafo . Los archivos de métricas de fuentes TeX utilizan números de punto fijo con signo de 32 bits y 12 bits fraccionarios.
  • Tremor , Toast y MAD son bibliotecas de software que decodifican los formatos de audio Ogg Vorbis , GSM Full Rate y MP3 respectivamente. Estos códecs utilizan aritmética de punto fijo porque muchos dispositivos de hardware de decodificación de audio no tienen una FPU.
  • El compresor de audio sin pérdida WavPack utiliza aritmética de punto fijo. La elección se justificó, entre otras cosas, por la preocupación de que las distintas reglas de redondeo de punto flotante en distintos hardware pudieran corromper la naturaleza sin pérdida de la compresión. [18]
  • La biblioteca de utilidades de Nest Labs, [19] proporciona un conjunto limitado de macros y funciones para números de punto fijo, particularmente cuando se trabaja con esos números en el contexto del muestreo de sensores y las salidas de sensores.
  • La especificación OpenGL ES 1.x incluye un perfil de punto fijo, ya que es una API orientada a sistemas integrados, que no siempre tienen una FPU.
  • Los programas dc y bc son calculadoras de precisión arbitraria , pero solo realizan un seguimiento de un número fijo de dígitos fraccionarios (especificado por el usuario).
  • Fractint representa números como números de punto fijo Q2.29 , [20] para acelerar el dibujo en PC antiguas con procesadores 386 o 486SX , que carecían de una FPU.
  • Doom fue el últimojuego de disparos en primera persona de id Software que utilizó una representación de punto fijo 16.16 para todos sus cálculos no enteros, incluidos el sistema de mapas, la geometría, la representación y el movimiento del jugador. Esta representación todavía se utiliza en los puertos de origen de Doom modernos .
  • El lenguaje de programación Q# para las computadoras cuánticas de Azure , que implementan puertas lógicas cuánticas , contiene una biblioteca numérica estándar para realizar aritmética de punto fijo en registros de qubits . [21]

Véase también

Referencias

  1. ^ "¿Cuál es la diferencia entre los formatos de punto fijo, punto flotante y numérico?". ElectronicDesign . 2017-08-31.
  2. ^ Documentación del lenguaje de programación Julia Paquete FixedPointNumbers.
  3. ^ Manual de PostgreSQL, sección 8.1.2. Números de precisión arbitraria
  4. ^ JTC1/SC22/WG14 (2008), estado de TR 18037: C integrado
  5. ^ Wiki de GCC, Soporte de aritmética de punto fijo
  6. ^ Uso de GCC, sección 5.13 Tipos de punto fijo
  7. ^ IBM Corporation, "Elementos numéricos". Sitio de documentación en línea, consultado el 5 de julio de 2021.
  8. ^ Documentación de Ada 83: "Fundamento, 5.3.2: Tipos de punto fijo". Consultado el 5 de julio de 2021.
  9. ^ ab "Apéndice A.2". Referencia del programador de la biblioteca DSP TMS320C64x (PDF) . Dallas, Texas, EE. UU.: Texas Instruments Incorporated . Octubre de 2003. SPRU565. Archivado (PDF) desde el original el 22 de diciembre de 2022 . Consultado el 22 de diciembre de 2022 .
  10. ^ "Glosario de documentación de la caja de herramientas de punto fijo de MathWorks". mathworks.com . Archivado desde el original el 2011-03-16 . Consultado el 2011-01-28 .
  11. ^ "Guía de depuradores ARM Developer Suite AXD y armsd". 1.2. ARM Limited . 2001 [1999]. Capítulo 4.7.9. AXD > AXD Facilities > Data formatting > Q-format. ARM DUI 0066D. Archivado desde el original el 4 de noviembre de 2017.
  12. ^ "Capítulo 4.7.9. AXD > AXD Facilities > Data formatting > Q-format". Guía de depuradores de AXD y armsd de RealView Development Suite (PDF) . 3.0. ARM Limited . 2006 [1999]. págs. 4–24. ARM DUI 0066G. Archivado (PDF) desde el original el 4 de noviembre de 2017.
  13. ^ "VisSim ahora es solidThinking Embed". www.vissim.com . solidThinking Inc.
  14. ^ Guía del usuario de PS2 GS, Capítulo 7.1 "Notas explicativas"
  15. ^ "El conjunto de instrucciones TrueType: tipos de datos".
  16. ^ "[Freetype] ¿Por qué 26.6?".
  17. ^ "Emulador Dolphin". Emulador Dolphin . 15 de marzo de 2014.
  18. ^ "Descripción técnica de WavPack". www.wavpack.com . Consultado el 13 de julio de 2015 .
  19. ^ Biblioteca de utilidades de Nest Labs
  20. ^ "Fractint, un pequeño código". Archivado desde el original el 27 de octubre de 2010. Consultado el 24 de octubre de 2005 .
  21. ^ "Introducción a la biblioteca de números cuánticos" . Consultado el 13 de noviembre de 2019 .

Lectura adicional

  • Matemáticas simples de punto fijo
  • Aritmética de punto fijo: una introducción
  • Representación de punto fijo y matemáticas fraccionarias
  • Una mirada calculada a la aritmética de punto fijo (PDF)
Retrieved from "https://en.wikipedia.org/w/index.php?title=Fixed-point_arithmetic&oldid=1245584238"