L’utilisation du double est-elle plus rapide que le flottement?

Les valeurs doubles stockent une plus grande précision et sont deux fois plus grandes qu’un float, mais les processeurs Intel sont-ils optimisés pour les flottants?

Autrement dit, les opérations doubles sont-elles aussi rapides ou plus rapides que les opérations flottantes pour +, -, * et /?

La réponse change-t-elle pour les architectures 64 bits?

Il n’y a pas un seul “processeur Intel”, notamment en ce qui concerne les opérations optimisées par rapport aux autres!

Les opérations doubles sont-elles aussi rapides ou rapides que les opérations flottantes pour +, -, * et /?

est “oui” – dans la CPU , sauf pour la division et sqrt qui sont un peu plus lents pour le double que pour le float . (En supposant que votre compilateur utilise SSE2 pour les maths FP scalaires, comme tous les compilateurs x86-64, et certains compilateurs 32 bits en fonction des options. Legacy x87 n’a pas de largeur différente dans les registres, seulement en mémoire) ), donc historiquement même sqrt et division étaient aussi lents pour le double ).

Par exemple, Haswell a un débit en divsd de 1 à 8 à 14 cycles (dépendant des données), mais un divss (scalaire unique) de 1 par 7 cycles. x87 fdiv correspond à un débit de 8 à 18 cycles. (Nombres de https://agner.org/optimize/ . La latence est en corrélation avec le débit pour la division, mais elle est supérieure aux chiffres de débit.)

Les versions float de nombreuses fonctions de bibliothèque telles que logf(float) et sinf(float) seront également plus rapides que log(double) et sin(double) , car elles ont beaucoup moins de bits de précision pour être correctes. Ils peuvent utiliser des approximations polynomiales avec moins de termes pour obtenir une précision totale pour le float vs le double


Cependant , prendre deux fois plus de mémoire pour chaque numéro implique clairement une charge plus lourde sur le ou les cache (s) et plus de bande passante mémoire pour remplir et renverser ces lignes de cache depuis / vers la RAM; le temps que vous vous souciez des performances d’une opération à virgule flottante est lorsque vous effectuez beaucoup d’opérations de ce type, de sorte que les considérations de mémoire et de cache sont cruciales.

La réponse de @ Richard souligne qu’il existe d’autres moyens d’effectuer des opérations FP (les instructions SSE / SSE2; le bon vieux MMX était uniquement en nombres entiers), particulièrement adapté aux opérations simples sur beaucoup de données (“SIMD”, instruction unique / données multiples). ) où chaque registre vectoriel peut contenir 4 flotteurs à simple précision ou seulement 2 flotteurs à double précision , cet effet sera donc encore plus marqué.

En fin de compte, vous devez effectuer un benchmark, mais selon ma prédiction, pour des benchmarks raisonnables (c.-à-d. Grands ;-), vous aurez avantage à vous en tenir à une seule précision (en supposant bien sûr que vous n’ayez pas besoin des bits supplémentaires de précision!-).

Si tous les calculs à virgule flottante sont effectués dans la FPU, alors non, il n’y a pas de différence entre un calcul double et un calcul float car les opérations à virgule flottante sont effectuées avec 80 bits de précision dans la stack FPU. Les entrées de la stack FPU sont arrondies, le cas échéant, pour convertir le format à virgule flottante 80 bits au format double ou float virgule flottante. Déplacer la sizeof(double) octets sizeof(double) vers / depuis la RAM par rapport à la sizeof(float) octets sizeof(float) est la seule différence de vitesse.

Si, toutefois, vous avez un calcul vectorisable, vous pouvez utiliser les extensions SSE pour exécuter quatre calculs float en même temps que deux double calculs. Par conséquent, une utilisation intelligente des instructions SSE et des registres XMM peut permettre un débit plus élevé sur les calculs qui utilisent uniquement des float .

Un autre point à considérer est si vous utilisez un GPU (la carte graphique). Je travaille avec un projet numériquement intensif, mais nous n’avons pas besoin de la possibilité de doubler. Nous utilisons des cartes GPU pour accélérer le traitement. Les GPU CUDA ont besoin d’un package spécial pour supporter le double, et la quantité de RAM locale sur un GPU est assez rapide, mais assez rare. En conséquence, l’utilisation de float double également la quantité de données que nous pouvons stocker sur le

Encore un autre point est la mémoire. Les chars prennent deux fois moins de RAM que les doubles. Si vous avez affaire à de très grands ensembles de données, cela peut être un facteur très important. Si utiliser double signifie que vous devez mettre en cache sur disque vs disque virtuel, votre différence sera énorme.

Donc, pour l’application avec laquelle je travaille, la différence est assez importante.

Dans les expériences d’ajout de 3,3 pour 2000000000 fois, les résultats sont les suivants:

 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 

Donc, le double est plus rapide et par défaut en C et C ++. Il est plus portable et par défaut dans toutes les fonctions de la bibliothèque C et C ++. Alos double a une précision nettement supérieure à celle du flottement.

Même Stroustrup recommande le double over float:

“La signification exacte de la précision simple, double et étendue est définie par l’implémentation. Choisir la bonne précision pour un problème où le choix est important nécessite une compréhension importante du calcul en virgule flottante. Si vous n’avez pas cette compréhension, des conseils, prenez le temps d’apprendre ou utilisez le double et espérez le meilleur. ”

Peut-être que le seul cas où vous devriez utiliser float au lieu de double est sur du matériel 64 bits avec un gcc moderne. Parce que le flotteur est plus petit; double est de 8 octets et float est de 4 octets.

Je veux juste append aux bonnes réponses déjà existantes que le __m256? famille de fonctions SIMD ( SIMD ) Les fonctions insortingnsèques C ++ fonctionnent sur 4 double en parallèle (par exemple, _mm256_add_pd ) ou sur 8 float en parallèle (par exemple, _mm256_add_ps ).

Je ne suis pas sûr que cela puisse se traduire par une accélération réelle , mais il semble possible de traiter deux fois plus de flottants par instruction lorsque SIMD est utilisé.

La seule réponse vraiment utile est la suivante: vous seul pouvez le dire. Vous devez évaluer vos scénarios. De petits changements dans les instructions et les schémas de mémoire pourraient avoir un impact significatif.

Cela aura certainement de l’importance si vous utilisez le matériel de type FPU ou SSE (le premier fait tout son travail avec une précision étendue de 80 bits, donc le double sera plus proche; plus tard, il sera natif à 32 bits, c’est-à-dire flottant).

Mise à jour: s / MMX / SSE / comme indiqué dans une autre réponse.

Le point flottant est normalement une extension de la CPU à usage général. La vitesse dépendra donc de la plate-forme matérielle utilisée. Si la plate-forme prend en charge les virgules flottantes, je serai surpris si des différences existent.