¿Por qué las flotillas siguen siendo parte del lenguaje Java cuando en su mayoría se recomiendan los dobles?

83

En todos los lugares que he visto, dice que double es superior a float en casi todos los aspectos. float se ha quedado obsoleto por double en Java, ¿por qué se sigue utilizando?

Programo mucho con Libgdx, y te obligan a usar float (deltaTime, etc.), pero me parece que es más fácil trabajar con double en términos de almacenamiento y memoria.

También leí Cuando hago usa float y cuándo usa doble , pero si float es realmente bueno para números con muchos dígitos después del punto decimal, entonces ¿por qué no podemos usar una de las muchas variaciones de%? double ?

¿Hay alguna razón para que la gente insista en usar flotadores aunque ya no tenga ventajas? ¿Es demasiado trabajo cambiarlo todo?

    
pregunta Eames 26.04.2016 - 18:08
fuente

6 respuestas

167

LibGDX es un marco utilizado principalmente para el desarrollo de juegos.

En el desarrollo de juegos, por lo general, tienes que hacer un montón de cálculos numéricos en tiempo real y cualquier rendimiento que puedas obtener es importante. Es por eso que los desarrolladores de juegos usualmente usan float cuando la precisión de float es lo suficientemente buena.

El tamaño de los registros FPU en la CPU no es lo único que debe considerar en este caso. De hecho, la mayor parte de los pesados números en el desarrollo del juego lo realiza la GPU, y Las GPU generalmente están optimizadas para flotadores, no dobles .

Y luego está también:

  • ancho de banda del bus de memoria (qué tan rápido puede cargar datos entre la RAM, la CPU y la GPU)
  • caché de CPU (lo que hace que el anterior sea menos necesario)
  • RAM
  • VRAM

que son todos recursos preciosos de los que obtienes el doble cuando usas 32bit float en lugar de 64bit double.

    
respondido por el Philipp 26.04.2016 - 19:41
fuente
57

Los flotadores utilizan la mitad de memoria que los dobles.

Es posible que tengan menos precisión que los dobles, pero muchas aplicaciones no requieren precisión. Tienen un rango mayor que cualquier formato de punto fijo de tamaño similar. Por lo tanto, llenan un nicho que necesita amplios rangos de números pero no necesita alta precisión y donde el uso de la memoria es importante. Los he usado para sistemas de redes neuronales grandes en el pasado, por ejemplo.

Al moverse fuera de Java, también se usan ampliamente en gráficos 3D, ya que muchas GPU las usan como su formato principal; al margen de los costosos dispositivos NVIDIA Tesla / AMD FirePro, el punto flotante de doble precisión es muy lento en las GPU.

    
respondido por el Jules 26.04.2016 - 19:51
fuente
47

Compatibilidad con versiones anteriores

Esta es la razón número uno para mantener el comportamiento en un ya existente idioma / biblioteca / ISA / etc.

Considera lo que sucedería si sacaran flotadores de Java. Libgdx (y miles de otras bibliotecas y programas) no funcionaría. Se requerirá mucho esfuerzo para actualizar todo, posiblemente años para muchos proyectos (solo mire la transición de Python 2 a Python 3 que rompe la compatibilidad). Y no todo se actualizará, algunas cosas se romperán para siempre porque los mantenedores las abandonaron, tal vez antes de lo que hubieran hecho porque les costaría más esfuerzo de lo que quieren actualizar, o porque ya no es posible para lograr lo que su software debía hacer.

Rendimiento

Los dobles de 64 bits toman el doble de memoria y casi siempre son más lentos de procesar que los flotadores de 32 bits (las raras excepciones son en las que se espera que la capacidad de flotación de 32 bits se use tan raramente o que no se haga ningún esfuerzo) optimice para ellos. A menos que esté desarrollando hardware especializado, no experimentará esto en un futuro cercano.)

Especialmente relevante para ti, Libgdx es una biblioteca de juegos. Los juegos tienden a ser más sensibles al rendimiento que la mayoría de los programas. Y las tarjetas gráficas para juegos (es decir, AMD Radeon y NVIDIA Geforce, no FirePro o Quadro) tienden a tener un rendimiento de punto flotante de 64 bits muy débil. Cortesía de Anandtech, aquí es cómo se compara el rendimiento de doble precisión con el rendimiento de precisión simple en algunos de AMD's y NVIDIA's mejores tarjetas de juegos disponibles (a partir de principios de 2016)

AMD
Card    R9 Fury X      R9 Fury       R9 290X    R9 290
FP64    1/16           1/16          1/8        1/8

NVIDIA
Card    GTX Titan X    GTX 980 Ti    GTX 980    GTX 780 Ti
FP64    1/32           1/32          1/32       1/24

Tenga en cuenta que las series R9 Fury y GTX 900 son más nuevas que las series R9 200 y GTX 700, por lo que el rendimiento relativo para el punto flotante de 64 bits está disminuyendo. Vuelve lo suficientemente lejos y encontrarás la GTX 580, que tenía una proporción de 1/8 como la serie R9 200.

1/32 del rendimiento es una penalización bastante grande que pagar si tienes una restricción de tiempo limitada y no ganas mucho al usar el doble más grande.

    
respondido por el 8bittree 26.04.2016 - 22:43
fuente
34

operaciones atómicas

Además de lo que otros ya han dicho, una desventaja específica de Java de double (y long ) es que no se garantiza que las asignaciones a tipos primitivos de 64 bits sean atomic . En la página Especificación del lenguaje Java, edición Java SE 8 , 660 (énfasis añadido):

  

17.7 Tratamiento no atómico de double y long

     

A los efectos del modelo de memoria del lenguaje de programación Java, una sola escritura en un valor no volátil de long o double se trata como dos escrituras separadas: una para cada mitad de 32 bits. Esto puede provocar una situación en la que un hilo ve los primeros 32 bits de un valor de 64 bits de una escritura y los segundos 32 bits de otra escritura.

Yuck.

Para evitar esto, debes declarar la variable de 64 bits con el volatile palabra clave, o use alguna otra forma de sincronización alrededor de las asignaciones.

    
respondido por el Kevin J. Chase 27.04.2016 - 07:53
fuente
3

Parece que otras respuestas pasaron por alto un punto importante: las arquitecturas SIMD pueden procesar menos / más datos dependiendo de si operan en double o float structs (por ejemplo, ocho valores flotantes a la vez o cuatro valores dobles a la vez).

Resumen de consideraciones de rendimiento

  • float puede ser más rápido en ciertas CPU (por ejemplo, ciertos dispositivos móviles).
  • float usa menos memoria, por lo que en grandes conjuntos de datos puede reducir sustancialmente la memoria total requerida (disco duro / RAM) y el ancho de banda consumido.
  • float puede hacer que una CPU consuma menos energía (no puedo encontrar una referencia, pero si no es posible, al menos parece plausible) para los cálculos de precisión simple en comparación con los cálculos de precisión doble.
  • float consume menos ancho de banda, y en algunas aplicaciones lo que importa.
  • Las arquitecturas SIMD pueden procesar tanto como el doble de la misma cantidad de datos porque generalmente.
  • float usa tanto como la mitad de la memoria caché en comparación con el doble.

Resumen de consideraciones de precisión

  • En muchas aplicaciones, float es suficiente
  • double tiene mucha más precisión de todos modos

Consideraciones de compatibilidad

  • Si sus datos deben enviarse a una GPU (por ejemplo, para un videojuego que utiliza OpenGL o cualquier otro API), el formato de punto flotante es considerablemente más rápido que double (esto se debe a que los fabricantes de GPU intentan aumentar el número de núcleos gráficos y, por lo tanto, intentan ahorrar la mayor cantidad de circuitos posible en cada núcleo, por lo que optimizan float permite crear GPU con más núcleos dentro)
  • Las GPU antiguas y algunos dispositivos móviles simplemente no pueden aceptar double como formato interno (para operaciones de renderizado 3D)

Consejos generales

  • En los procesadores de escritorio modernos (y probablemente en una buena cantidad de procesadores móviles), básicamente puede asumir que el uso de variables double temporales en la pila le da una precisión adicional gratuita (precisión adicional sin penalización de rendimiento).
  • Nunca use más precisión de la que necesita (es posible que no sepa cuánta precisión realmente necesita).
  • En ocasiones, solo estás forzado por el rango de valores (algunos valores serían infinitos si estuvieras usando float , pero pueden ser valores limitados si estás usando double )
  • Usar solo float o solo double ayuda al compilador a SIMD-ify las instrucciones.

Vea los comentarios a continuación de PeterCordes para obtener más información.

    
respondido por el GameDeveloper 27.04.2016 - 19:16
fuente
0

Aparte de las otras razones que fueron mencionadas:

Si tiene datos de medición, ya sean presiones, flujos, corrientes, voltajes o lo que sea, a menudo esto se hace con hardware que tiene un ADC.

Un ADC normalmente tiene 10 o 12 bits, 14 o 16 bits son más raros. Pero mantengámonos en el de 16 bits uno: si se mide a escala completa, tiene una precisión de 1/65535. Eso significa que un cambio de 65534/65535 a 65535/65535 es solo este paso: 1/65535. Eso es más o menos 1.5E-05. La precisión de un flotador es de alrededor de 1E-07, así que mucho mejor. Eso significa que no pierdes nada al utilizar float para almacenar estos datos.

Si realiza excesivos con flotadores, tiene un desempeño ligeramente peor que con doubles en términos de precisión, pero a menudo no necesita esa precisión, ya que a menudo no le importa si acaba de medir un voltaje de 2 V o 2.00002 V. De manera similar, si convierte este voltaje en una presión, no le importa si tiene 3 bar o 3.00003 bar.

    
respondido por el glglgl 29.04.2016 - 19:07
fuente

Lea otras preguntas en las etiquetas