Pourquoi les flottants font-ils toujours partie du langage Java alors que les doublons sont plutôt recommandés?


84

À chaque endroit où j'ai regardé, il est dit que doublec'est supérieur à floatpresque à tous les égards. floata été rendu obsolète par doubleJava, pourquoi est-il toujours utilisé?

Je programme beaucoup avec Libgdx, et ils vous obligent à utiliser float(deltaTime, etc.), mais il me semble que doublec'est simplement plus facile de travailler en termes de stockage et de mémoire.

Je lis aussi Quand utilisez-vous float et quand utilisez-vous double , mais si ce floatn'est vraiment bon que pour les nombres avec beaucoup de chiffres après la virgule, alors pourquoi ne pourrions-nous pas simplement utiliser l'une des nombreuses variations de double?

Y a-t-il une raison pour laquelle les gens insistent pour utiliser des flotteurs même s'ils ne présentent plus aucun avantage? Est-ce trop de travail pour tout changer?



58
Comment dans le monde avez-vous déduit que "les flottants ne valent vraiment que pour les nombres avec beaucoup de chiffres après la virgule" à partir des réponses à cette question?! Ils disent le contraire !
Ordous

20
@Eames Notez comment il est écrit "chiffres", pas "chiffres". Les flotteurs sont pires quand vous avez besoin de précision ou de portée, ils sont meilleurs quand vous avez besoin de beaucoup de données pas très précises. C'est ce que disent ces réponses.
Ordous

29
Pourquoi avons-nous byteet shortet intquand il y a long?
user253751

15
Une question beaucoup plus pertinente est "pourquoi voudriez-vous supprimer un mot-clé et un type de données primitif d'un langage avec des décennies de code qui ne ferait que se briser sans raison"?
Sara

Réponses:


169

LibGDX est un framework principalement utilisé pour le développement de jeux.

En développement de jeu, vous devez généralement effectuer un nombre considérable de calculs en temps réel, ainsi que toutes les performances que vous pouvez obtenir. C'est pourquoi les développeurs de jeux utilisent généralement float chaque fois que sa précision est suffisante.

La taille des registres FPU dans la CPU n'est pas la seule chose à prendre en compte dans ce cas. En fait, la plupart des problèmes de calcul dans le développement de jeux sont effectués par le GPU, et les GPU sont généralement optimisés pour les floats, pas pour les doublons .

Et puis il y a aussi:

  • Bande passante du bus mémoire (à quelle vitesse vous pouvez pelleter des données entre RAM, CPU et GPU)
  • Cache de la CPU (ce qui rend la précédente moins nécessaire)
  • RAM
  • VRAM

qui sont toutes des ressources précieuses dont vous obtenez deux fois plus lorsque vous utilisez float 32 bits au lieu de 64 bits double.


2
Je vous remercie! Cela a vraiment aidé parce que vous avez expliqué en détail ce que l'utilisation de la mémoire a changé et pourquoi
Eames

7
De plus, pour les opérations SIMD, les valeurs 32 bits peuvent avoir un débit deux fois supérieur. Comme le souligne la réponse de 8bittree , les GPU sont encore plus pénalisés en termes de performances avec une double précision.
Paul A. Clayton

5
De nombreux pipelines graphiques prennent même en charge les demi-flotteurs 16 bits pour améliorer les performances lorsque la précision est suffisante.
Adi Shavit

22
@phresnel Tous sont. Vous devez déplacer des positions, mettre à jour des données et quoi. Et c'est la partie simple . Ensuite, vous devez restituer (= lire, faire pivoter, redimensionner et traduire) les textures, les distances, le rendre au format écrans ... Il y a beaucoup à faire.
Sebb

8
@phresnel en tant qu'ancien vice-président des opérations d'une entreprise de développement de jeux, je vous assure que presque chaque jeu comporte une tonne de calculs. Notez qu'il est généralement contenu dans des bibliothèques et 100% abstraites de l'ingénieur, j'espère qu'ils comprennent et respectent le fait que tout ce travail est en cours. La racine carrée inverse magique, n'importe qui?
CorsiKa

57

Les flotteurs utilisent deux fois moins de mémoire que les doubles.

Ils ont peut-être moins de précision que les doubles, mais de nombreuses applications n'exigent pas de précision. Ils ont une gamme plus large que tout format de point fixe de taille similaire. Par conséquent, ils occupent un créneau qui nécessite de grands nombres de chiffres mais qui n’a pas besoin d’une précision élevée et où l’utilisation de la mémoire est importante. Je les utilisais par exemple dans le cadre de grands réseaux de neurones.

En dehors de Java, ils sont également largement utilisés dans les graphiques 3D, car de nombreux GPU les utilisent comme format principal. En dehors des périphériques très coûteux de NVIDIA Tesla / AMD FirePro, la virgule flottante double précision est très lente sur les GPU.


8
Parlant de réseaux de neurones, CUDA prend actuellement en charge les variables à virgule flottante demi-précision (16 bits), encore moins précises mais avec une empreinte mémoire encore plus réduite, en raison de l'utilisation accrue d'accélérateurs pour le travail d'apprentissage automatique.
JAB

Et lorsque vous programmez des FPGA, vous avez tendance à sélectionner manuellement le nombre de bits à la fois pour la mantisse et l'exposant: v
Sebi

48

Rétrocompatibilité

C'est la raison numéro un pour conserver le comportement dans une langue / bibliothèque / ISA / etc. déjà existante .

Pensez à ce qui se produirait s’ils retiraient les flotteurs de Java. Libgdx (et des milliers d'autres bibliothèques et programmes) ne fonctionnerait pas. Il faudra beaucoup d'efforts pour mettre le tout à jour, probablement des années pour de nombreux projets (il suffit de regarder la transition en amont de la compatibilité entre Python 2 et Python 3). Et tout ne sera pas mis à jour, certaines choses seront brisées pour toujours parce que les mainteneurs les ont abandonnées, peut-être plus tôt qu’elles ne l’auraient été parce qu’il faudrait plus d’efforts qu’elles ne veulent mettre à jour, ou parce qu’il n’est plus possible d’accomplir ce que leur logiciel était supposé faire.

Performance

Les doubles 64 bits occupent deux fois plus de mémoire et sont presque toujours plus lents à traiter que les bits flottants 32 bits (les très rares exceptions étant celles où la capacité 32 bits flottants est censée être utilisée si rarement, voire pas du tout, qu'aucun effort n'a été fait pour les optimiser. Sauf si vous développez pour du matériel spécialisé, cela ne se produira pas dans un avenir proche.)

Pour vous, Libgdx est une bibliothèque de jeux. Les jeux ont tendance à être plus sensibles aux performances que la plupart des logiciels. Et les cartes graphiques de jeu (AMD Radeon et NVIDIA Geforce, et non FirePro ou Quadro) ont tendance à avoir de très faibles performances en virgule flottante 64 bits. Grâce à Anandtech, voici comment comparer les performances en double précision à celles en simple précision de certaines des meilleures cartes de jeu disponibles d' AMD et de NVIDIA (à partir de début 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

Notez que les séries R9 Fury et GTX 900 sont plus récentes que les séries R9 200 et GTX 700, de sorte que les performances relatives pour la virgule flottante 64 bits sont en baisse. Retournez assez loin et vous trouverez la GTX 580, qui avait un rapport de 1/8 comme la série R9 200.

1/32 de la performance est une pénalité assez lourde à payer si vous avez une contrainte de temps serrée et que vous ne gagnez pas beaucoup en utilisant le double plus grand.


1
Notez que les performances en virgule flottante 64 bits sont en baisse par rapport aux performances en 32 bits en raison d'instructions 32 bits de plus en plus optimisées, et non en raison de la diminution des performances réelles en 64 bits. cela dépend aussi du repère utilisé; Je me demande si le déficit de performances 32 bits mis en évidence dans ces tests est dû à des problèmes de bande passante de mémoire ainsi qu'à la vitesse de calcul réelle
sig_seg_v

Si vous parlez de performances DP dans les cartes graphiques, vous devez absolument mentionner Titan / Titan Black. Les deux disposent de mods qui permettent à la carte d’atteindre un tiers des performances, au détriment des performances en simple précision.
SGR

@sig_seg_v Dans certains cas, les performances 64 bits diminuent de manière absolue, pas seulement de manière relative. Consultez ces résultats pour un test de performance Folding @ Home en double précision, dans lequel une GTX 780 Ti bat à la fois une GTX 1080 (une autre carte au format 1/32) et une carte 980 Ti, et côté AMD, la 7970 (une carte au 1/4) , ainsi que les R9 290 et R9 290X ont tous battu la série R9 Fury. Comparez cela à la version à simple précision de la référence , où les nouvelles cartes dépassent toutes les performances de leurs prédécesseurs.
8bittree

36

Opérations atomiques

Outre ce que d'autres ont déjà dit, un inconvénient spécifique à Java de double(et long) est que les assignations à des types primitifs 64 bits ne sont pas forcément atomiques . Extrait de la spécification du langage Java, édition Java SE 8 , page 660 (non souligné dans l'original):

17.7 Traitement non atomique du doubleetlong

Pour les besoins du modèle de mémoire en langage de programmation Java, une seule écriture dans une valeur longou une doublevaleur non volatile est traitée comme deux écritures distinctes: une dans chaque moitié de 32 bits. Cela peut entraîner une situation dans laquelle un thread voit les 32 premiers bits d'une valeur de 64 bits d'une écriture et les 32 derniers bits d'une autre écriture.

Beurk.

Pour éviter cela, vous devez déclarer la variable 64 bits avec levolatile mot clé ou utiliser une autre forme de synchronisation autour des assignations.


2
N'avez-vous pas besoin de synchroniser l'accès simultané aux ints et aux floats pour éviter les pertes de mises à jour et les rendre volatiles pour empêcher la mise en cache trop lourde? Est-ce que je me trompe en pensant que la seule chose que l'atomicité int / float empêche, c'est qu'ils ne peuvent jamais contenir de valeurs "mixtes" qu'ils n'étaient pas supposés défendre?
Traubenfuchs

3
@ Traubenfuchs C'est ce qui est garanti là-bas. Le terme que j'ai entendu utiliser pour cela est "déchirure" et je pense que cela résume assez bien l'effet. Le modèle de langage de programmation Java garantit que les valeurs 32 bits, une fois lues, auront une valeur qui leur a été écrite à un moment donné. C'est une garantie étonnamment précieuse.
Cort Ammon

Ce point à propos de l'atomicité est extrêmement important. Wow, j'avais oublié ce fait important. Contre-intuitif que nous pourrions avoir tendance à penser que les primitives sont atomiques par nature. Mais pas atomique dans ce cas.
Basil Bourque

3

Il semble que d’autres réponses aient manqué un point important: les architectures SIMD peuvent traiter moins / plus de données selon qu’elles fonctionnent sur doubleou des floatstructures (par exemple, huit valeurs flottantes à la fois ou quatre valeurs doubles à la fois).

Résumé des considérations de performance

  • float peut être plus rapide sur certains processeurs (par exemple, certains appareils mobiles).
  • float utilise moins de mémoire, ce qui peut réduire considérablement la mémoire totale requise (disque dur / RAM) et la bande passante consommée dans les grands ensembles de données.
  • float peut faire en sorte que le processeur consomme moins d’énergie (je ne trouve pas de référence, mais si ce n’est pas possible, cela semble au moins plausible) pour les calculs à simple précision par rapport aux calculs à double précision.
  • float consomme moins de bande passante, et dans certaines applications, cela compte.
  • Les architectures SIMD peuvent traiter jusqu'à deux fois la même quantité de données car d'habitude.
  • float utilise autant que la moitié de la mémoire cache par rapport au double.

Résumé des considérations de précision

  • Dans de nombreuses applications floatsuffit
  • double a beaucoup plus de précision quand même

Considérations de compatibilité

  • Si vos données doivent être soumises à un GPU (par exemple, pour un jeu vidéo utilisant OpenGL ou toute autre API de rendu), le format de virgule flottante est considérablement plus rapide que double(c'est parce que les fabricants de GPU tentent d'augmenter le nombre de cœurs graphiques et ainsi, ils essaient de sauvegarder autant de circuits que possible dans chaque cœur, donc l’optimisation floatpermet de créer des GPU avec plus de cœurs à l’intérieur)
  • Les anciens GPU et certains appareils mobiles ne peuvent tout simplement pas être acceptés doublecomme format interne (pour les opérations de rendu 3D)

Conseils généraux

  • Sur les processeurs de bureau modernes (et probablement sur un grand nombre de processeurs mobiles), vous pouvez en principe supposer que l’utilisation de doublevariables temporaires sur la pile donne une précision supplémentaire gratuite (précision supplémentaire sans perte de performances).
  • N'utilisez jamais plus de précision que nécessaire (vous pouvez ne pas savoir quelle précision vous avez réellement besoin).
  • Parfois, vous êtes forcé par la plage de valeurs (certaines valeurs seraient infinies si vous utilisez float, mais peuvent être limitées si vous utilisez double)
  • Utiliser seulement floatou seulement doublebeaucoup aide le compilateur à simplifier les instructions.

Voir les commentaires ci-dessous de PeterCordes pour plus d'informations.


1
doubletemporaries est gratuit uniquement sur x86 avec la FPU x87, pas avec SSE2. La vectorisation automatique d'une boucle avec des éléments doubletemporaires signifie le décompactage floatde double, ce qui nécessite une instruction supplémentaire, et vous traitez la moitié moins d'éléments par vecteur. Sans vectorisation automatique, la conversion peut généralement se produire à la volée pendant un chargement ou un stockage, mais cela signifie des instructions supplémentaires lorsque vous mélangez des flottants et des doublons dans des expressions.
Peter Cordes

1
Sur les processeurs x86 modernes, div et sqrt sont plus rapides pour float que double, mais les autres choses ont la même vitesse (sans tenir compte du problème de largeur du vecteur SIMD, ni de la bande passante de la mémoire / du cache bien sûr).
Peter Cordes

@PeterCordes Merci d'avoir développé certains points. Je n'étais pas au courant de la disparité div et sqrt
GameDeveloper Le

0

Outre les autres raisons évoquées:

Si vous avez des données de mesure, qu'il s'agisse de pressions, de débits, de courants, de tensions ou autres, cela se fait souvent avec du matériel doté d'un CAN.

Un ADC a typiquement 10 ou 12 bits, les 14 ou 16 bits étant plus rares. Mais restons sur le 16 bits - si vous mesurez à la pleine échelle, vous avez une précision de 1/65535. Cela signifie qu'un changement de 65534/65535 en 65535/65535 correspond à cette étape - 1/65535. C'est à peu près 1.5E-05. La précision d'un flotteur est d'environ 1E-07, donc bien meilleure. Cela signifie que vous ne perdez rien en utilisant floatpour stocker ces données.

Si vous effectuez des calculs excessifs avec des flotteurs, vos performances sont légèrement moins bonnes qu'en doublestermes de précision, mais souvent vous n’avez pas besoin de cette précision, car vous ne vous souciez pas souvent de mesurer une tension de 2 V ou de 2 000 000 V. De même. , si vous convertissez cette tension en pression, vous n’aurez rien à faire si vous avez 3 bars ou 3.00003 bars.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.