Articulo de referencia

Aritmética de punto fijo

En informática , el punto fijo es un método para representar números fraccionarios (no enteros) almacenando una cantidad fija de dígitos de su parte fraccionaria. Por ejemplo, l...

En informática , el punto fijo es un método para representar números fraccionarios (no enteros) almacenando una cantidad fija de dígitos de su parte fraccionaria. Por ejemplo, las cantidades en dólares suelen almacenarse con exactamente dos dígitos fraccionarios, que representan los centavos (1/100 de dólar). De forma 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 numérica de punto fijo suele contrastarse con la representación de punto flotante, que es más compleja y requiere mayor capacidad de cálculo .

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

Cuando se muestran números decimales de punto fijo para su lectura, los dígitos fraccionarios suelen estar separados de los de la parte entera por un carácter decimal (normalmente "." en inglés, pero "," u otro símbolo en muchos otros idiomas). Sin embargo, internamente no existe tal separación, y la distinción entre ambos grupos de dígitos la definen únicamente los programas que manejan dichos números.

La representación de punto fijo era la norma en las calculadoras mecánicas . Dado que la mayoría de los procesadores modernos cuentan con una unidad de punto flotante (FPU) rápida, las representaciones de punto fijo en las implementaciones basadas en procesadores ahora se utilizan solo en situaciones especiales, como en microprocesadores y microcontroladores integrados de bajo costo ; en aplicaciones que requieren alta velocidad, bajo consumo de energía o un área de chip pequeña , como el 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, donde las fracciones de centavos deben redondearse a centavos enteros de maneras estrictamente prescritas; y la evaluación de funciones mediante búsqueda en tablas , o cualquier aplicación donde los números racionales deban representarse sin errores de redondeo (lo cual permite el punto fijo, pero no el punto flotante). La representación de punto fijo sigue siendo la norma para las implementaciones de matrices de puertas programables en campo (FPGA), ya que la compatibilidad con punto flotante en una FPGA requiere muchos más recursos que la compatibilidad con punto fijo. [ 1 ]

Representación

La representación en coma fija de un número fraccionario es, esencialmente, un número entero que se multiplica implícitamente por un factor de escala fijo. Por ejemplo, el valor 1,23 se puede almacenar en una variable como el número entero 123 con un factor de escala implícito de 1/100. Esta representación permite que las unidades lógicas aritméticas enteras estándar realicen cálculos con números racionales .

Los valores negativos se suelen representar en formatos binarios 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 estará indicado por el bit más significativo (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 ( 1111 0101 ) 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 formato signo-magnitud , en cuyo caso el signo nunca se incluye en el número de bits de fracción implícitos. Esta variante se utiliza más comúnmente en la aritmética decimal de punto fijo. Por lo tanto, el entero decimal de 5 dígitos con signo (−00 025 ) 10 , tomado con −3, +5 y +12 dígitos de fracción decimal implícitos, representaría los valores −25/10 −3  =−25 000 , −25/10 5  =−0,000 25 , y −25/10 12  =−0,000 000 000 025 , respectivamente.

Un programa suele asumir que todos los valores de punto fijo que se almacenarán en una variable determinada, o que se generarán mediante una instrucción específica , tendrán el mismo factor de escala. Este parámetro suele ser elegido por el programador en función de la precisión requerida y el rango de valores que se almacenarán.

El factor de escala de una variable o fórmula puede no aparecer explícitamente en el programa. Por lo tanto , las buenas prácticas de programación exigen que se proporcione en la documentación , al menos como un comentario en el código fuente .

Elección de factores de escala

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

Sin embargo, ocasionalmente se pueden utilizar otros factores de escala; por ejemplo, una cantidad fraccionaria de horas puede representarse 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 preciso, los valores de punto fijo representados con un factor de escala S pueden tener un error de hasta ±0,5 × S en el valor entero almacenado. Por lo tanto, los factores de escala más pequeños generalmente producen resultados más precisos.

Por otro lado, un factor de escala menor implica un rango menor de valores que se pueden almacenar en una variable de programa determinada. El valor máximo de punto fijo que se puede almacenar en una variable es el mayor valor entero que se puede almacenar en ella, multiplicado por el factor de escala, y lo mismo ocurre con el valor mínimo. Por ejemplo, la tabla siguiente muestra el factor de escala implícito S , los valores mínimo y máximo 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, según el número f de bits fraccionarios implícitos.

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. Proporcionan conversiones más consistentes entre valores de punto fijo y de punto flotante que la escala de 2 n . El lenguaje de programación Julia implementa ambas versiones. [ 2 ]

Valores exactos

Cualquier fracción binaria a / 2m , como 1/16 o 17/32, puede representarse con exactitud en punto fijo, con un factor de escala de potencia de dos 1/ 2n, donde n m . Sin embargo, la mayoría de las fracciones decimales, como 0,1 o 0,123, son fracciones periódicas infinitas en base 2 y, por lo tanto, no pueden representarse de esa manera.

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

En términos más generales, un número racional a / b , con a y b primos entre sí y b positivo, puede representarse exactamente en punto fijo binario solo si b es una potencia de 2; y en punto fijo decimal solo si b no tiene factores primos distintos de 2 o 5.

Comparación con punto flotante

Los cálculos de punto fijo pueden ser más rápidos o usar menos hardware que los de punto flotante. Si el rango de los valores a representar se conoce de antemano y está 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 decimal entre 0 y 1, una representación de punto fijo puede tener un error menor que1,2 × 10 −10 , mientras que la representación de punto flotante estándar IEEE 754 puede tener un error de hasta596 × 10 −10 porque 9 de los bits se asignan al signo y exponente del factor de escala dinámica que no se utiliza en este rango limitado de valores. Para una grabación de audio digital que requiere menos de Con un margen dinámico de 40 dB , un sistema de punto fijo de 32 bits tiene una relación señal/ruido superior a la de un sistema de punto flotante.

Los programas que utilizan cálculos de punto fijo suelen ser más portátiles que los que utilizan punto flotante, ya que no dependen de la disponibilidad de una unidad de punto flotante (FPU). Esta ventaja era especialmente significativa antes de la adopción generalizada del estándar de punto flotante IEEE , 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 ordenador.

Muchos procesadores integrados carecen de una unidad de punto flotante (FPU), ya que las unidades aritméticas de enteros requieren muchas menos puertas lógicas y ocupan una superficie de chip considerablemente menor que una FPU; además, la emulación por software de punto flotante en dispositivos de baja velocidad sería demasiado lenta para la mayoría de las aplicaciones. Los chips de CPU de los primeros ordenadores personales y consolas de videojuegos , como el Intel 386 y el 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 su rango, es decir, el factor de escala S. En cambio, 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, al igual que los propios valores.

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 equivalentes de punto flotante. Aplicar técnicas de linealización al truncamiento, como el tramado o la conformación de ruido, es más sencillo dentro de la aritmética de punto fijo. Por otro lado, el uso de punto fijo requiere mayor cuidado por parte del programador. Evitar el desbordamiento requiere estimaciones mucho más precisas para los rangos de las 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 utilizar punto flotante por bloques , que es un entorno de punto fijo donde cada matriz (bloque) de datos de punto fijo se escala con un exponente común en una sola palabra.

Aplicaciones

Un uso común de la notación decimal de punto fijo es el almacenamiento de valores monetarios, para lo cual las complejas 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ó de punto flotante a punto fijo a partir de la versión 1.6 por este motivo. [ 3 ]

El punto fijo binario (escalado binario) se utilizó ampliamente desde finales de la década de 1960 hasta la de 1980 para la computación en tiempo real con alta carga matemática, como la simulación de vuelo y los algoritmos de control de centrales nucleares . Todavía se utiliza en muchas aplicaciones de procesamiento digital de señales (DSP) y en microprocesadores personalizados. Los cálculos que involucran ángulos utilizan 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 discreta del coseno que se utilizan para comprimir imágenes JPEG .

Los instrumentos electrónicos, como los contadores de electricidad y los relojes digitales, suelen utilizar polinomios para compensar errores introducidos, por ejemplo, debido a la temperatura o al voltaje de la fuente de alimentación. Los coeficientes se obtienen 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 favorablemente 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 el número 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, basta con sumar o restar los enteros subyacentes; el resultado tendrá su factor de escala implícito común y, por lo tanto, 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 se produce un desbordamiento, ocurre como con los enteros ordinarios del mismo signo. En los casos sin signo y con signo mediante complemento a dos, el comportamiento de desbordamiento es bien conocido como un grupo finito .

Si los operandos tienen factores de escala diferentes, deberán convertirse a un factor de escala común antes de la operación.

Multiplicación

Para multiplicar dos números de punto fijo, basta con multiplicar los dos números enteros subyacentes y suponer que el factor de escala del resultado es el producto de sus factores de escala.

(p/q) * (r/s) = pr/qs

El resultado será exacto, sin redondeo, siempre que no exceda el límite de la variable receptora. (En concreto, en la multiplicación de enteros, el producto puede tener hasta el doble de la suma de los dos factores).

Por ejemplo, al multiplicar los números 123 escalado por 1/1000 (0,123) y 25 escalado por 1/10 (2,5) se obtiene el entero 123×25 = 3075 escalado por (1/1000)×(1/10) = 1/10000, es decir, 3075/10000 = 0,3075. Como otro ejemplo, al multiplicar el primer número por 155 escalado implícitamente por 1/32 (155/32 = 4,84375) se obtiene el entero 123×155 = 19065 con un 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 sea una potencia de dos. Después de la multiplicación, este factor de escala se puede eliminar mediante un desplazamiento a la derecha. Este desplazamiento es sencillo y rápido en la mayoría de las computadoras.

Cuando se utiliza el desplazamiento a la derecha o una instrucción típica de división entera (como la división entera en C y la instrucción idiv de x86), el resultado es equivalente a una división con redondeo hacia abajo (floor(x/y)). Se puede utilizar un método con redondeo para reducir el error introducido. Son posibles tres variantes según la elección del criterio de desempate:

  • El redondeo al alza es posible añadiendo un sumando de redondeo equivalente a la mitad del factor de escala antes del desplazamiento. La prueba: redondeo(x/y) = piso(x/y + 0,5) = piso((x + y/2)/y). Si y = 2^n, esto es equivalente a (x + 2^(n−1)) >> n (donde >> representa un desplazamiento a la derecha).
  • Redondear hacia abajo a la mitad es, por analogía, floor((x - y/2)/y) o (x - 2^(n-1)) >> n.
  • El redondeo a la mitad más cercano implica básicamente tomar una decisión adicional además del redondeo a la mitad más cercano. Es un poco más complicado, pero aún así no requiere bifurcaciones en una CPU. [ 4 ]

Estos métodos de redondeo se pueden utilizar en cualquier escalado mediante división entera. Por ejemplo, también son aplicables al análisis del reescalado.

División

La división de números de punto fijo puede entenderse como la división de dos fracciones con denominadores potencialmente diferentes (factores de escala). Con p / q y r / s (donde p, q y rs son todos enteros), el enfoque ingenuo consiste en reorganizar la fracción para formar un nuevo factor de escala (s/q):

(p/q) / (r/s) = (p÷r) / (s÷q)

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.

Con valores de s y q muy similares, el algoritmo anterior da como resultado un factor de escala demasiado grueso. Esto se puede mejorar convirtiendo primero el dividendo a un factor de escala menor. Digamos que reducimos el factor de escala n veces; entonces, en su lugar, calculamos:

(p/q) / (r/s) = (np/nq) / (r/s) = (np÷r) / (s÷nq)

Por ejemplo, si a = 1,23 se representa como 123 con un factor de escala de 1/100, y b = 6,25 se representa como 6250 con un factor de escala de 1/1000, entonces la división simple de los enteros produce 123÷6250 = 0 (redondeado) con un factor de escala de (1/100)/(1/1000) = 10. Si a se convierte primero a 1.230.000 con un factor de escala de 1/1000000, el resultado será 1.230.000÷6250 = 197 (redondeado) con un factor de escala de 1/1000 (0,197). El valor exacto de 1,23/6,25 es 0,1968.

Otra forma de entender la escala es considerar la división, la operación inversa de la multiplicación. Si la multiplicación produce un factor de escala más fino, es lógico que el dividendo también deba tener un factor de escala más fino para recuperar el valor original.

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 exactitud del resultado de una división;
  • Para asegurar 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 coste 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 razón R / S. Así, por ejemplo, para convertir el valor 1,23 = 123/100 de un 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, lo que da como resultado la representación 1230/1000.

Si el factor de escala es una potencia de la base utilizada internamente para representar el número entero, cambiarlo solo requiere eliminar los dígitos de menor orden o añadir ceros. Sin embargo, esta operación debe conservar el signo. En la representación en complemento a dos, esto implica 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 número 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 enteros correspondientes y dividir explícitamente el resultado por S. Es posible que el resultado deba redondearse y que 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 de 1/100, el número 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 coma flotante a coma fija, se puede multiplicar por el factor de escala S y redondear el resultado al entero más cercano. Es importante asegurarse de que el resultado quepa en la variable o registro de destino. Dependiendo del factor de escala, el tamaño de almacenamiento y el rango de números de entrada, la conversión podría no requerir redondeo.

Para convertir un número de punto fijo a punto flotante, se puede convertir el entero a punto flotante y luego dividirlo por el factor de escala S. Esta conversión puede implicar redondeo si el valor absoluto del entero es mayor que 2²⁴ ( para punto flotante IEEE de precisión simple binaria) o de 2⁵³ ( para precisión doble). Puede producirse un desbordamiento o un subdesbordamiento si | S | es muy grande o muy pequeño, respectivamente.

Soporte de hardware

Escalado y renormalización

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

Las primeras computadoras, como la IBM 1620 y la Burroughs B3500, utilizaban una representación decimal codificada en binario (BCD) para los números enteros, concretamente en base 10, donde cada dígito decimal se codificaba de forma independiente con 4 bits. Algunos procesadores, como los microcontroladores, aún pueden utilizarla. En estas máquinas, la conversión de los factores de escala decimal se puede realizar mediante desplazamientos de bits o 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 oscilar entre −1 y casi +1). Este soporte puede incluir una instrucción de multiplicación con renormalización: la conversión de escala del producto de 2 n −2 a n −1 bits fraccionarios. Si la CPU no ofrece esta función, el programador debe guardar el producto en un registro o variable temporal de tamaño suficiente e implementar 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 de 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 sin escalar se reduce módulo 2ⁿ , donde n es el tamaño del área de almacenamiento. En particular, se pierde el bit de signo, lo que puede alterar radicalmente el signo y la magnitud del valor.

Algunos procesadores pueden activar un indicador de desbordamiento de hardware o generar una excepción cuando se produce un desbordamiento. Otros, en cambio, utilizan aritmética de saturación : si el resultado de una suma o resta se desborda, almacenan el valor de mayor magnitud que cabe en el área de almacenamiento y que tiene el signo correcto.

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

Soporte de lenguajes informáticos

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

La mayoría de estos lenguajes se diseñaron entre 1955 y 1990. Los lenguajes más modernos generalmente no ofrecen tipos de datos de punto fijo ni compatibilidad con la conversión de factores de escala. Esto también ocurre con varios lenguajes antiguos que aún son muy populares, como FORTRAN , C y C++ . La amplia disponibilidad de procesadores de punto flotante rápidos, con un comportamiento estrictamente estandarizado, ha reducido considerablemente la demanda de compatibilidad con punto fijo binario. De manera similar, la compatibilidad con punto flotante decimal en algunos lenguajes de programación, como C# y Python , ha eliminado la mayor parte de la necesidad de compatibilidad con 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 que admita tipos enteros explícitos.

Por otro lado, todas las bases de datos relacionales y la notación SQL admiten aritmética decimal de punto fijo y almacenamiento de números. PostgreSQL tiene una característica especial.numéricotipo para almacenamiento exacto de números con hasta 1000 dígitos. [ 5 ]

Además, en 2008 la Organización Internacional de Normalización (ISO) publicó un borrador de informe técnico para extender el lenguaje de programación C con tipos de datos de punto fijo, en beneficio de los programas que se ejecutan en procesadores DSP integrados. Se proponen dos tipos principales de datos: _Fract (parte fraccionaria con una precisión mínima de 7 bits) y _Accum (_Fract con al menos 4 bits de parte entera). [ 6 ] La Colección de Compiladores GNU (GCC) admite este borrador. [ 7 ] [ 8 ]

Ejemplos detallados

Multiplicación de punto fijo decimal

Supongamos que existe la siguiente multiplicación con dos números de punto fijo de 3 cifras 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}}}

Nótese cómo, dado que hay 3 decimales, mostramos los ceros finales. Para volver a caracterizar esto como una multiplicación entera, primero debemos multiplicar por1000 (=103){\displaystyle 1000\ (=10^{3})}, moviendo todos los decimales a posiciones enteras, luego multiplicaremos por1/1000 (=103){\displaystyle 1/1000\ (=10^{-3})}para volver a colocarlos. La ecuación ahora se ve así:

(10.500)(103)(1.050)(103)(103)(103)=(10500)(1050)(106)=11025000(106)=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 forma equivalente si elegimos una base diferente, concretamente la base 2 para computación, ya que un desplazamiento de bits es lo mismo que una multiplicación o división por un factor 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=23+211=200,5=210,05=0,00001100112{\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í, nuestra multiplicación se convierte en

(1010.100)(23)(1.0000110011)(210)(213)=(1010100)(10000110011)(213)=(10110000010111100)(213)=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 usando 16 bits de fracción. Para representar los dos números, se multiplican por 2¹⁶ , obteniendo 78 643.2 y 367 001.6 ; y se redondean estos valores al entero más cercano, obteniendo 78 643 y 367 002. Estos números caben cómodamente en una palabra de 32 bits con formato de complemento a dos con signo.

Al multiplicar estos enteros, se obtiene el entero de 35 bits 28 862 138 286 con 32 bits de fracción, sin redondeo. Cabe destacar 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 o registro entero con signo de 64 bits .

Si el resultado se va a almacenar en el mismo formato que los datos, con 16 bits de fracción, ese entero debe dividirse por 2 16 , lo que da aproximadamente 440 401 .28, y luego redondearse al entero más cercano. Este efecto se puede lograr sumando 2 15 y luego desplazando el resultado 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 los operandos). El resultado correcto sería 1.2 × 5.6 = 6.72.

Para un ejemplo más complejo, supongamos que los números 1.2 y 5.6 se representan en formato de punto fijo de 32 bits con 30 y 20 bits de fracción, respectivamente. Al escalarlos por 2³⁰ y 2²⁰ se obtienen 1²⁸⁸⁴⁰¹⁸⁸ y 5 872 025,6, que se redondean a 1²⁸⁸⁴⁰¹⁸⁹ y 5 872 026 , respectivamente . Ambos números aún 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 elegimos representar este valor en formato fijo de 16 bits con signo y 8 bits de fracción, debemos dividir el producto entero por 2 50−8 = 2 42 y redondear el resultado; lo cual 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 más bien el intervalo entre 3439/2 9 y 3441/2 9 (aproximadamente 6,719 ± 0,002).

Notaciones

Se han utilizado diversas 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 (0/1 u otra representación alternativa) y b el número total de bits.

  • La notación Q fue definida por Texas Instruments . [ 9 ] Se escribe para especificar un valor binario de punto fijo con signo con f bits fraccionarios; por ejemplo, especifica un entero con signo en notación de complemento a dos con un factor de escala 1/2 15 . El código especifica además que el número tiene m bits en la parte entera del valor, sin contar el bit de signo. Así, describiría un formato binario de punto fijo con 1 bit entero y 30 bits fraccionarios, que podría almacenarse como un entero de complemento a dos de 32 bits con un factor de escala 1/2 30 . [ 9 ] [ 10 ]QfQ15Qm.fQ1.30
    • 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 propuesta Embedded C utiliza .f para fracción sin signo, s .f para fracción con signo, mf para acumulador sin signo y s m.f para acumulador con signo. Esto traduciría lo anterior a s1.30, aunque este no es un tipo válido ni para fracción ni para acumulador: en versiones válidas, m es al menos 4 y, dependiendo del tipo subyacente , f es al menos 7, 15 o 23. Nótese la s sin cursiva: simplemente se antepone como una letra.
  • El lenguaje de programación COBOL originalmente admitía precisión fija decimal con tamaño arbitrario y escala decimal, cuyo formato se especificaba "gráficamente" con la directiva PIC . Por ejemplo, PIC S9999V99especificaba un entero decimal de 6 dígitos con signo y magnitud, con dos dígitos de fracción decimal. [ 13 ]
  • Esta construcción se utiliza en el lenguaje de programación PL/I para especificar un tipo de dato binario con signo de punto fijo con un total de p bits (sin incluir el signo) y f bits en la parte fraccionaria; es decir, un entero con signo de p + 1 bits 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.REAL FIXED BINARY (p,f)
  • En el lenguaje de programación Ada , un tipo de datos numéricos se puede especificar mediante, por ejemplo, . Los límites decimales se traducen a la siguiente potencia de dos, por lo que significa una representación de punto fijo que consiste en un entero binario con signo en formato de complemento a dos con al menos 8 bits de fracción (proporcionando un factor de escala 1/256) y 7 bits de signo y magnitud (asegurando un rango real de −64,00 a casi +64,00): un total mínimo de 15 bits. En una computadora de 16 bits, el bit sobrante se asigna a la parte fraccionaria. También se permiten restricciones de rango asimétricas, [ 14 ] aunque la implementación subyacente permanece simétrica con respecto a 0. [ 15 ] Las versiones más recientes de Ada permiten especificar un factor de escala exacto (incluidos los que no son potencias de dos) usando (especificación de aspecto), o, si el factor es una potencia de 10, a través de un punto fijo decimal.typeFisdelta0.005range-50.0..50.0 'Small => 0.005
  • Esta notación se ha utilizado para referirse a un formato binario fijo con m bits en la parte entera; el resto de la palabra (normalmente 32 bits) son bits fraccionarios. Por ejemplo, los valores máximo y mínimo que se pueden almacenar en un número con signo son aproximadamente 32767,9999847 y -32768,0, respectivamente.BmB16
  • La empresa VisSim solía 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 un factor de escala de 1/2 bm . Esto significaría un número de 16 bits con 1 bit en la parte entera y 15 en la parte fraccionaria. [ 16 ]fxm.bfx1.16
  • La guía del usuario del PS2 GS ( "Graphics Synthesizer" ) utiliza la notación , donde s especifica la presencia (0 o 1) del bit de signo. [ 17 ] Por ejemplo, 0:5:3 representa un entero sin signo de 8 bits con un factor de escala de 1/2 3 .s:m:f
  • El lenguaje de programación LabVIEW utiliza la notación para especificar los parámetros de los números de punto fijo 'FXP'. El componente 's' puede ser '+' o '±', que indican un número sin signo o un número con signo en complemento a dos, respectivamente. El componente 'b' representa el número total de bits, y 'm' es el número de bits de la parte entera.<s,b,m>

Ejemplos de aplicaciones de software

  • El popular formato de fuente TrueType utiliza punto fijo binario con signo de 32 bits con 26 bits a la izquierda del decimal para algunos valores numéricos en sus instrucciones. [ 18 ] Este formato se eligió para proporcionar la cantidad mínima de precisión requerida para el hinting y por razones de rendimiento. [ 19 ]
  • Con la excepción de la Nintendo 64 , todos los juegos 3D para la quinta generación de consolas de videojuegos , incluyendo la 3DO , PlayStation , Sega Saturn y Atari Jaguar [ 20 ] , 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 punto fijo de 16 bits con 12 bits fraccionarios, mientras que los coprocesadores VDP de Sega Saturn utilizaban 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, emplea 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 tipográfico . Los archivos de métricas de fuente 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 disponen de una unidad de punto fijo (FPU).
  • El compresor de audio sin pérdidas WavPack utiliza aritmética de punto fijo. Esta elección se justificó, entre otras cosas, por la preocupación de que las diferentes reglas de redondeo de punto flotante en distintos dispositivos pudieran corromper la naturaleza sin pérdidas de la compresión. [ 21 ]
  • La biblioteca Nest Labs Utilities, [ 22 ] proporciona un conjunto limitado de macros y funciones para números de punto fijo, particularmente cuando se trata de esos números en el contexto del muestreo de sensores y salidas de sensores.
  • La especificación OpenGL ES 1.x incluye un perfil de punto fijo, ya que es una API destinada a sistemas embebidos, que no siempre disponen de una unidad de punto flotante (FPU).
  • Los programas dc y bc son calculadoras de precisión arbitraria , pero solo registran un número fijo (especificado por el usuario) de dígitos fraccionarios.
  • Fractint representa los números como números de punto fijo Q2.29 , [ 23 ] para acelerar el dibujo en PC antiguas con procesadores 386 o 486SX , que carecían de una FPU.
  • Doom fue el último juego de disparos en primera persona de id Software en utilizar una representación de punto fijo de 16,16 bits para todos sus cálculos no enteros, incluyendo el sistema de mapas, la geometría, el renderizado y el movimiento del jugador. Esta representación todavía se utiliza en las versiones modernas del código fuente de Doom .
  • El lenguaje de programación Q# para las computadoras cuánticas 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 cúbits . [ 24 ]

Véase también

Referencias

  1. "¿Cuál es la diferencia entre los formatos de punto fijo, punto flotante y numéricos?" . ElectronicDesign . 31/08/2017.
  2. Documentación del lenguaje de programación Julia Paquete FixedPointNumbers .
  3. "¿Qué hay de nuevo?" . code.gnucash.org . Consultado el 10 de septiembre de 2025 .
  4. Daniel Lemire, "Redondeo de enteros a números pares de manera eficiente", en el blog de Daniel Lemire, 16 de abril de 2020, https://lemire.me/blog/2020/04/16/rounding-integers-to-even-efficiently/ .
  5. Manual de PostgreSQL, sección 8.1.2. Números de precisión arbitraria
  6. JTC1/SC22/WG14 (2008), estado de TR 18037: C embebido
  7. Wiki de GCC, Soporte para aritmética de punto fijo
  8. Usando GCC, sección 5.13 Tipos de punto fijo
  9. 1 2 "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) del original el 22 de diciembre de 2022. Recuperado el 22 de diciembre de 2022 .
  10. "Glosario de documentación de MathWorks Fixed-Point Toolbox" . mathworks.com . Archivado del original el 16 de marzo de 2011. Consultado el 28 de enero de 2011 .
  11. "Guía de depuradores ARM Developer Suite AXD y armsd" . 1.2. ARM Limited . 2001 [1999]. Capítulo 4.7.9. AXD > Funciones de AXD > Formato de datos > Formato Q. ARM DUI 0066D.{{cite web}}: CS1 maint: servicio de archivado obsoleto ( enlace )
  12. "Capítulo 4.7.9. AXD > Funciones AXD > Formato de datos > Formato Q". Guía de depuración de RealView Development Suite AXD y armsd (PDF) . 3.0. ARM Limited . 2006 [1999]. págs. 4–24 . ARM DUI 0066G. Archivado (PDF) del original el 4 de noviembre de 2017. 
  13. IBM Corporation, " Elementos numéricos ". Sitio de documentación en línea, consultado el 5 de julio de 2021.
  14. Documentación de Ada 83: " Fundamentos, 5.3.2: Tipos de punto fijo ". Consultado el 5 de julio de 2021.
  15. "Tipos de punto fijo" .
  16. "VisSim ahora es solidThinking Embed" . www.vissim.com . solidThinking Inc.
  17. Guía del usuario de PS2 GS, Capítulo 7.1 "Notas explicativas"
  18. "El conjunto de instrucciones TrueType: tipos de datos" . 22 de septiembre de 2020.
  19. " [ Freetype ] ¿Por qué 26.6 ?" . 
  20. "Emulador de delfines" . Emulador de delfines . 15/03/2014.
  21. "Descripción técnica de WavPack" . www.wavpack.com . Consultado el 13 de julio de 2015 .
  22. Biblioteca de utilidades de Nest Labs
  23. "Fractint, un pequeño código" . Archivado del original el 27 de octubre de 2010. Consultado el 24 de octubre de 2005 .
  24. "Introducción a la Biblioteca de Numéricos Cuánticos" . Consultado el 13 de noviembre de 2019 .

Lecturas adicionales

  • Matemáticas simples de punto fijo
  • Aritmética de punto fijo: una introducción
  • Representación de punto fijo y matemáticas fraccionarias. Archivado el 4 de noviembre de 2017 en Wayback Machine.
  • Una mirada calculada a la aritmética de punto fijo ( PDF)