c++ - numericos - punto flotante normalizado
Punto flotante versus punto fijo: ¿cuáles son los pros/contras? (8)
El tipo de punto flotante representa un número al almacenar sus dígitos significativos y su exponente por separado en palabras binarias separadas para que quepa en 16, 32, 64 o 128 bits.
El tipo de punto fijo almacena números con 2 palabras, una representa la parte entera, otra representa la parte más allá de la raíz, en exponentes negativos, 2 ^ -1, 2 ^ -2, 2 ^ -3, etc.
Los flotadores son mejores porque tienen un rango más amplio en un sentido de exponente, pero no si uno quiere almacenar un número con más precisión para un cierto rango, por ejemplo, solo usa un número entero de -16 a 16, por lo tanto usa más bits para mantener los dígitos más allá del radix .
En términos de rendimiento, ¿cuál tiene el mejor rendimiento o hay casos en que algunos son más rápidos que los otros?
En la programación de videojuegos, ¿todos usan puntos flotantes porque la FPU lo hace más rápido, o porque la caída del rendimiento es insignificante, o hacen su propio tipo fijo?
¿Por qué no hay ningún tipo fijo en C / C ++?
A nivel de código, la aritmética de punto fijo es simplemente aritmética de enteros con un denominador implícito.
Para muchas operaciones aritméticas simples, las operaciones de punto fijo e entero son esencialmente las mismas. Sin embargo, hay algunas operaciones en las que los valores intermedios deben representarse con un mayor número de bits y luego redondearse. Por ejemplo, para multiplicar dos números de punto fijo de 16 bits, el resultado debe almacenarse temporalmente en 32 bits antes de volver a normalizar (o saturar) de nuevo a punto fijo de 16 bits.
Cuando el software no aprovecha la vectorización (como SIMD o GPGPU basada en CPU), el aritmérico de punto fijo y entero es más rápido que FPU. Cuando se utiliza la vectorización, la eficiencia de la vectorización es mucho más importante, por lo que las diferencias de rendimiento entre el punto fijo y el punto flotante son discutibles.
Algunas arquitecturas proporcionan implementaciones de hardware para ciertas funciones matemáticas, como sin
, cos
, atan
, sqrt
, solo para tipos de punto flotante. Algunas arquitecturas no proporcionan ninguna implementación de hardware en absoluto. En ambos casos, las bibliotecas especializadas de software matemático pueden proporcionar esas funciones utilizando solo aritmética de punto fijo o entero. A menudo, tales bibliotecas proporcionarán múltiples niveles de precisión, por ejemplo, respuestas que solo son precisas hasta N bits de precisión, que es menor que la precisión total de la representación. Las versiones de precisión limitada pueden ser más rápidas que la versión de mayor precisión.
Debe tener cuidado al hablar de "precisión" en este contexto.
Para el mismo número de bits en representación, el valor máximo de punto fijo tiene más bits significativos que cualquier valor de punto flotante (porque el formato de punto flotante tiene que dar algunos bits al exponente), pero el valor mínimo de punto fijo tiene menos que cualquier otro -un valor de punto flotante normalizado (porque el valor de punto fijo desperdicia la mayor parte de su mantisa en ceros iniciales).
Además, dependiendo de la forma en que se divide el número de punto fijo, el valor de punto flotante puede representar números más pequeños , lo que significa que tiene una representación más precisa de "pequeño pero no cero".
Y así.
Depende de en qué estés trabajando. Si estás usando un punto fijo, pierdes precisión; tienes que seleccionar el número de lugares después del lugar decimal (lo que no siempre es lo suficientemente bueno). En coma flotante, no debe preocuparse por esto, ya que la precisión ofrecida es casi siempre lo suficientemente buena para la tarea en cuestión: utiliza una implementación de formulario estándar para representar el número.
Los pros y los contras se reducen a la velocidad y los recursos. En las plataformas modernas de 32 bits y 64 bits no hay necesidad de usar un punto fijo. La mayoría de los sistemas vienen con FPU incorporadas que están cableadas para ser optimizadas para operaciones de punto fijo. Además, la mayoría de los intrínsecos de CPU modernos vienen con operaciones como el conjunto SIMD que ayuda a optimizar los métodos basados en vectores mediante la vectorización y el desenrollado. Así que el punto fijo solo viene con un lado negativo.
En sistemas embebidos y microcontroladores pequeños (8 bits y 16 bits) es posible que no tenga un FPU ni conjuntos de instrucciones extendidas. En cuyo caso, puede verse obligado a utilizar métodos de punto fijo o los conjuntos de instrucciones de punto flotante limitado que no son muy rápidos. Por lo tanto, en estas circunstancias, el punto fijo será una mejor opción, o incluso su única opción.
El punto fijo se usa ampliamente en sistemas DSP y embebidos, donde a menudo el procesador de destino no tiene FPU, y el punto fijo puede implementarse de manera razonablemente eficiente utilizando una ALU entera.
En términos de rendimiento, es probable que varíe según la arquitectura y la aplicación de destino. Obviamente, si no hay FPU, entonces el punto fijo será considerablemente más rápido. Cuando tengas una FPU también dependerá de la aplicación. Por ejemplo, realizar algunas funciones como sqrt () o log () será mucho más rápido cuando se admita directamente en el conjunto de instrucciones en lugar de implementarlo de forma algorítmica.
No hay un tipo de punto fijo incorporado en C o C ++, me imagino porque (o al menos C) fueron concebidos como lenguajes de nivel de sistemas y la necesidad de punto fijo es algo específica del dominio, y quizás también porque en un procesador de propósito general existe Normalmente no hay soporte directo de hardware para el punto fijo.
En C ++, la definición de una clase de tipo de datos de punto fijo con sobrecargas de operador adecuadas y funciones matemáticas asociadas puede superar fácilmente este inconveniente. Sin embargo, hay soluciones buenas y malas para este problema. Un buen ejemplo se puede encontrar aquí: http://www.drdobbs.com/cpp/207000448 . El enlace al código en ese artículo está roto, pero lo ftp://66.77.27.238/sourcecode/ddj/2008/0804.zip en ftp://66.77.27.238/sourcecode/ddj/2008/0804.zip
Esa definición cubre un subconjunto muy limitado de implementaciones de punto fijo.
Sería más correcto decir que en un punto fijo solo se almacena la mantisa y el exponente es una constante determinada a priori. No hay ningún requisito para que el punto binario caiga dentro de la mantisa, y definitivamente no hay ningún requisito para que caiga en un límite de palabra. Por ejemplo, todos los siguientes son "punto fijo":
- Mantisa de 64 bits, escalada en 2 -32 (esto se ajusta a la definición listada en la pregunta)
- Mantisa de 64 bits, escalada por 2 -33 (ahora las partes enteras y fraccionarias no se pueden separar por un límite de octeto)
- Mantisa de 32 bits, escalada en 2 4 (ahora no hay parte fraccionaria)
- Mantisa de 32 bits, escalada en 2 -40 (ahora no hay parte entera)
Las GPU tienden a usar un punto fijo sin parte entera (normalmente una mantisa de 32 bits escalada en 2 -32 ). Por lo tanto, las API como OpenGL y Direct3D a menudo usan tipos de punto flotante que son capaces de mantener estos valores. Sin embargo, manipular la mantisa de enteros a menudo es más eficiente, por lo que estas API también permiten especificar coordenadas (en el espacio de textura, espacio de color, etc.) de esta manera.
En cuanto a su afirmación de que C ++ no tiene un tipo de punto fijo, no estoy de acuerdo. Todos los tipos de enteros en C ++ son tipos de puntos fijos. Se suele suponer que el exponente es cero, pero esto no es necesario y tengo un poco de código DSP de punto fijo implementado en C ++ de esta manera.
La diferencia entre el punto flotante y la matemática de enteros depende de la CPU que tenga en mente. En los chips de Intel, la diferencia no es grande en relojes. Int math aún es más rápido porque hay varias ALU enteras que pueden funcionar en paralelo. Los compiladores también son inteligentes al usar instrucciones de cálculo de direcciones especiales para optimizar la suma / multiplicación en una sola instrucción. La conversión también cuenta como una operación, así que simplemente elige tu tipo y apégate a ella.
En C ++ puede crear su propio tipo para las matemáticas de punto fijo. Simplemente defina como estructura con un int y anule las sobrecargas apropiadas y haga que hagan lo que normalmente hacen más un cambio para colocar la coma en la posición correcta.
No usas float en los juegos porque es más rápido o más lento que lo usas porque es más fácil implementar los algoritmos en punto flotante que en punto fijo. Está asumiendo que la razón tiene que ver con la velocidad de cómputo y esa no es la razón, tiene que ver con la facilidad de programación.
Por ejemplo, puede definir el ancho de la pantalla / ventana gráfica desde 0.0 a 1.0, la altura de la pantalla 0.0 a 1.0. La profundidad de la palabra 0.0 a 1.0. y así. Matrix math, etc. hace que las cosas sean realmente fáciles de implementar. Realice todos los cálculos de esa manera hasta el punto en que necesite calcular píxeles reales en un tamaño de pantalla real, por ejemplo, 800x400. Proyecte el rayo desde el ojo hasta el punto en el objeto en el mundo y calcule dónde perfora la pantalla, usando 0 a 1 matemática, luego multiplique x por 800, y por 400 y coloque ese píxel.
el punto flotante no almacena el exponente y la mantisa por separado y la mantisa es un número ridículo, lo que queda después del exponente y el signo, como 23 bits, no 16 o 32 o 64 bits.
la matemática de punto flotante en su núcleo utiliza lógica de punto fijo con lógica adicional y pasos adicionales requeridos. Por definición, la comparación entre manzanas y manzanas es más barata porque no es necesario manipular los datos en el camino hacia el alu ni tener que manipular los datos al salir (normalizar). Cuando agrega IEEE y toda su basura que agrega aún más lógica, más ciclos de reloj, etc. (infinito debidamente firmado, silencio y señalización de nans, diferentes resultados para la misma operación si hay un controlador de excepción habilitado). Como alguien señaló en un comentario en un sistema real en el que puede hacer arreglos y flotar en paralelo, puede aprovechar algunos o todos los procesadores y recuperar algunos relojes de esa manera. tanto la velocidad de reloj fija como la flotante pueden aumentarse utilizando vastas cantidades de bienes raíces de chips, las fijas seguirán siendo más baratas, pero la flotación puede acercarse a velocidades fijas utilizando este tipo de trucos y operaciones en paralelo.
Un problema que no se cubre es que las respuestas son el consumo de energía. Aunque depende en gran medida de la arquitectura de hardware específica, por lo general, la FPU consume mucha más energía que la ALU en la CPU, por lo tanto, si apunta a aplicaciones móviles en las que el consumo de energía es importante, vale la pena considerar la implantación del algoritmo en un punto fijo.