¿Está usando el doble más rápido que el flotador?

Los valores dobles almacenan una mayor precisión y son el doble del tamaño de un flotante, pero ¿las CPU Intel están optimizadas para flotadores?

Es decir, ¿las operaciones dobles son tan rápidas o más rápidas que las operaciones de flotación para +, -, * y /?

¿La respuesta cambia para las architectures de 64 bits?

¡No hay una sola “CPU Intel”, especialmente en términos de qué operaciones están optimizadas con respecto a otras !, pero la mayoría de ellas, a nivel de CPU (específicamente dentro de la FPU), son tales que la respuesta a su pregunta:

son operaciones dobles tan rápidas o más rápidas que las operaciones de flotación para +, -, * y /?

es “sí” – dentro de la CPU , excepto para división y sqrt que son algo más lentos para el double que para el float . (Suponiendo que su comstackdor usa SSE2 para matemática escalar FP, como lo hacen todos los comstackdores x86-64, y algunos comstackdores de 32 bits dependiendo de las opciones. Legacy x87 no tiene anchos diferentes en los registros, solo en la memoria (se convierte en cargar / almacenar ), por lo que históricamente incluso sqrt y división eran tan lentos para el double ).

Por ejemplo, Haswell tiene un rendimiento de divsd de uno por cada 8 a 14 ciclos (dependiente de datos), pero un divss (sencillo escalar) de uno por cada 7 ciclos. x87 fdiv tiene un fdiv 8 a 18 ciclos. (Números de https://agner.org/optimize/ . La latencia se correlaciona con el rendimiento de la división, pero es más alta que los números de rendimiento).

Las versiones float de muchas funciones de biblioteca como logf(float) y sinf(float) también serán más rápidas que log(double) y sin(double) , porque tienen muchos menos bits de precisión para hacerlo bien. Pueden usar aproximaciones polinomiales con menos términos para obtener una precisión total para float vs. double


Sin embargo , ocupar el doble de memoria para cada número implica claramente una carga más pesada en la memoria caché y más ancho de banda de memoria para llenar y dertwigr esas líneas de caché de / a la RAM; El tiempo que le importa el rendimiento de una operación de coma flotante es cuando realiza muchas de estas operaciones, por lo que las consideraciones de memoria y caché son cruciales.

La respuesta de @ Richard señala que también hay otras formas de realizar operaciones de FP (las instrucciones SSE / SSE2, el antiguo MMX era solo de enteros), especialmente adecuado para operaciones simples en muchos datos (“SIMD”, instrucción única / datos múltiples ) donde cada registro vectorial puede empaquetar 4 flotadores de precisión simple o solo 2 de precisión doble , por lo que este efecto será aún más marcado.

Al final, tienes que comparar, pero mi predicción es que para los puntos de referencia razonables (es decir, grandes ;-), encontrarás la ventaja de seguir con la precisión simple (suponiendo, por supuesto, que no necesitas los bits adicionales de ¡precisión!-).

Si todos los cálculos de coma flotante se realizan dentro de la FPU, entonces, no, no hay diferencia entre un cálculo double y uno float porque las operaciones de punto flotante se realizan realmente con 80 bits de precisión en la stack de FPU. Las entradas de la stack de FPU se redondean según corresponda para convertir el formato de punto flotante de 80 bits al formato de coma flotante double o flotante. Mover sizeof(double) bytes a / desde RAM frente a sizeof(float) bytes es la única diferencia en velocidad.

Sin embargo, si tiene un cálculo vectorializable, puede usar las extensiones SSE para ejecutar cuatro cálculos float al mismo tiempo que dos cálculos double . Por lo tanto, el uso inteligente de las instrucciones SSE y los registros XMM puede permitir un mayor rendimiento en los cálculos que solo usan float .

Otro punto a considerar es si está usando GPU (la tarjeta gráfica). Trabajo con un proyecto que es numéricamente intensivo, pero no necesitamos la precisión que ofrece el doble. Usamos tarjetas GPU para ayudar a acelerar aún más el procesamiento. Las GPU de CUDA necesitan un paquete especial para admitir el doble, y la cantidad de RAM local en una GPU es bastante rápida, pero bastante escasa. Como resultado, usar float también duplica la cantidad de datos que podemos almacenar en el

Sin embargo, otro punto es la memoria. Los flotadores toman la mitad de RAM que los dobles. Si se trata de conjuntos de datos MUY grandes, este puede ser un factor realmente importante. Si usa doble significa que tiene que almacenar en caché en disco contra ram puro, su diferencia será enorme.

Entonces, para la aplicación con la que estoy trabajando, la diferencia es bastante importante.

En experimentos de agregar 3.3 por 2000000000 veces, los resultados son:

 Summation time in s: 2.82 summed value: 6.71089e+07 // float Summation time in s: 2.78585 summed value: 6.6e+09 // double Summation time in s: 2.76812 summed value: 6.6e+09 // long double 

Entonces el doble es más rápido y predeterminado en C y C ++. Es más portátil y el valor predeterminado en todas las funciones de la biblioteca C y C ++. Alos double tiene una precisión significativamente mayor que el flotador.

Incluso Stroustrup recomienda doble sobre el flotante:

“El significado exacto de la precisión simple, doble y extendida está definido por la implementación. Elegir la precisión adecuada para un problema donde la elección importa requiere una comprensión significativa del cálculo en coma flotante. Si no tiene esa comprensión, obtenga consejos, tómese el tiempo para aprender, o use el doble y espere lo mejor “.

Quizás el único caso en el que debe usar flotante en lugar de doble es en hardware de 64 bits con un gcc moderno. Porque el flotador es más pequeño; el doble tiene 8 bytes y el flotante tiene 4 bytes.

Solo quiero agregar a las excelentes respuestas ya existentes que el __m256? familia de mismas instrucciones de datos múltiples ( SIMD ) Las funciones intrínsecas de C ++ operan en 4 s double en paralelo (por ej. _mm256_add_pd ), o 8 float en paralelo (por ej. _mm256_add_ps ).

No estoy seguro de si esto puede traducirse en una velocidad real , pero parece posible procesar 2x tantos flotadores por instrucción cuando se usa SIMD.

La única respuesta realmente útil es: solo tú puedes decirlo. Necesita comparar sus escenarios. Pequeños cambios en la instrucción y los patrones de memoria podrían tener un impacto significativo.

Ciertamente importará si está usando el hardware de tipo FPU o SSE (el anterior hace todo su trabajo con una precisión extendida de 80 bits, por lo que el doble estará más cerca; más tarde es de 32 bits, es decir, flotado).

Actualización: s / MMX / SSE / como se indicó en otra respuesta.

El punto flotante es normalmente una extensión de la CPU de propósito general. Por lo tanto, la velocidad dependerá de la plataforma de hardware utilizada. Si la plataforma tiene soporte de punto flotante, me sorprendería si hay alguna diferencia.