À propos de la précision en virgule flottante et pourquoi l’utilisons-nous toujours

38

La virgule flottante a toujours été gênante pour la précision sur les grands mondes.

Cet article explique les coulisses et offre l’alternative évidente: les nombres à points fixes. Certains faits sont vraiment impressionnants, comme:

"Bien 64 bits de précision vous permettent d'atteindre la distance la plus éloignée entre Pluton et le Soleil (7,4 milliards de km) avec une précision inférieure au micromètre."

Une précision inférieure au micromètre est plus importante que tout besoin en ips (pour les positions et même les vitesses), et vous permettrait de construire de très grands mondes.

Ma question est la suivante: pourquoi utilisons-nous toujours la virgule flottante si le point fixe présente de tels avantages? La plupart des API de rendu et des bibliothèques de physique utilisent une virgule flottante (et souffrent de ses inconvénients, les développeurs doivent donc les contourner).

Sont-ils tellement plus lents?

De plus, comment pensez-vous que les moteurs planétaires évolutifs tels que outerra ou l'infini gèrent la grande échelle? Utilisent-ils un point fixe pour les positions ou ont-ils un algorithme de division d'espace?

system_is_b0rken
la source
3
Le dernier bit "en plus" devrait probablement être une question distincte afin que le principal ne soit pas égaré.
Tetrad
Je veux comprendre comment forcer un point fixe ... Mon jeu comporte toutes sortes d'erreurs étranges car Lua utilise le FPU, et le violon DirectX avec le FPU aussi ... J'ai vu des choses comme 2 * 9000 = 17995 ou 500 * 10 = 4897 c'est vraiment idiot. Mais la pire erreur est probablement celle qui est discutée dans les forums Ogre3D, où 1 + 5 = 4.
speeder
3
N'a pas justifié un commentaire; mais si vous décidez d'utiliser un point fixe, Q-Floats ( en.wikipedia.org/wiki/Q_(number_format) ) est votre ami. ils sont ridiculement rapides et faciles à mettre en œuvre.
Jonathan Dickinson
Donc, pour résumer, dois-je rester avec des points flottants (si je travaille en Java ou en Python)? - Gastón Il y a 26 minutes
Gastón

Réponses:

20

Si vous me permettez une fiche éhontée, je vais vous donner un exemple tiré d'un vrai jeu sur lequel je travaille (lien vidéo YouTube).

Le jeu propose un monde infini, généré de manière procédurale, sur un moteur physique. Il utilise une virgule flottante simple précision. Après quelques centaines de mètres d’espace de jeu, des problèmes de précision commencent à se poser (et s’aggravent de plus en plus par rapport à l’origine).

Ma solution? Tous les 200 m environ, je ramène le monde entier de 200 m vers l'origine (si vous souhaitez trouver et essayer l'un des prototypes sur mon site et afficher le calque de débogage [mondial], vous verrez que cela se produit).

Pourquoi ne pas utiliser un point fixe? Ou double précision? Au lieu de la simple précision? Car tout le reste utilise une virgule flottante simple précision!

Le moteur physique que j'utilise l'utilise, XNA l'utilise, les données chargées sur la carte graphique sont formatées en virgule flottante simple précision. Même le langage lui - même est conçu pour fonctionner avec des nombres à virgule flottante - écrire et (plus important encore) lire 0.5fest beaucoup plus facile que 0x80000000L.

C'est simplement une question de facilité en pratique. Et le gagnant est clairement conscient des problèmes de précision en virgule flottante et de l’ écriture. relativement simples, «déplacer le monde à zéro» (ou mettre en œuvre le partitionnement d’espace ou ce qui convient à votre jeu).

Et enfin un autre exemple - Orbiter est un jeu (de simulation, vraiment) qui a vraiment besoin de se soucier de la précision. Pas seulement dans l'espace mais aussi dans le temps (accélération du temps et corps en orbite - ne voulez pas qu'ils tombent du ciel, maintenant). Il utilise également des nombres à virgule flottante et utilise un hack pour maintenir la stabilité.

Andrew Russell
la source
Je me suis toujours demandé s'il serait peut-être plus facile pour certaines applications de déplacer tout le reste et de garder le "lecteur" à l'origine. Intéressant de voir que je ne suis pas le seul!
dash-tom-bang
J'aime ton raisonnement. Je voudrais juste souligner que lorsqu'il s'agit de jeux qui impliquent une mise en réseau, le point fixe semble avoir moins de bizarreries / déviations (la prédiction du client est plus précise).
Jonathan Dickinson
Je ne comprends pas très bien votre argument. Et au fait, pourquoi les langues n’ont-elles pas encore implémenté les points fixes? Bien sûr, cela semble être une raison de tirer pour utiliser des flottants, mais cela n'explique pas pourquoi le point fixe n'a pas été implémenté partout.
jokoon
@jokoon Je pensais que ma réponse était assez claire. Pourquoi le point fixe n'est-il pas implémenté partout? Il suffit de regarder Wikipedia: "Très peu de langages informatiques incluent une prise en charge intégrée des valeurs à virgule fixe, car pour la plupart des applications, les représentations en virgule flottante binaire ou décimale sont généralement plus simples à utiliser et suffisamment précises ." Un bon concepteur sait quoi omettre - et quelque chose qui duplique la fonctionnalité de manière à rendre très facile pour un programmeur de se tirer une balle dans le pied est un bon candidat.
Andrew Russell
D'accord. Les processeurs actuels exécutent très facilement les instructions en virgule flottante. Les instructions ont un excellent débit et la plupart n'ont qu'une latence plus longue que les instructions entières.
Doug65536
11

Premièrement - oui, ils sont beaucoup plus rapides. Même si vous pouvez obtenir un fonctionnement à point fixe aussi rapide qu’un FPU "normal", le point réel à virgule flottante comporte des instructions avantageuses telles que fsel pour arrêter les branches ou SIMD pour travailler sur plusieurs flotteurs à la fois. Les GPU utilisent également la virgule flottante, au moins dans leurs interfaces utilisateur.

Deuxièmement, 64 bits vous amène également assez loin en virgule flottante - la plupart des gens utilisent encore 32, mais l’avantage principal est qu’ils évoluent. Cette échelle à points fixes a une précision fixe. Que vous mesuriez le soleil en direction de Pluton ou de l’autre côté de la rue, vous obtenez la même précision. La virgule flottante vous donnera des résultats beaucoup plus précis lorsque toutes les valeurs impliquées sont plus petites. Étant donné que les bibliothèques de physique génériques sont censées fonctionner de manière passable avec de nombreux jeux à différentes échelles (et que certains d'entre eux peuvent avoir des échelles très différentes), ils doivent utiliser une sorte de nombre qui fonctionne à plusieurs échelles.


la source
5

Un autre point important à souligner est que les flotteurs ne sont pas si inexacts que les gens ici semblent le penser. Un float de 32 bits a une précision entière de 24 bits sur 24 bits. Cela signifie qu’elle est au moins aussi précise que la valeur d’un point fixe à 24 bits pour une plage donnée. Tandis que les flottants deviennent moins précis plus la valeur est grande, une valeur de point fixe débordera tout simplement et s’enroulera à un moment donné. Réduire la précision est une meilleure solution de secours. Les flotteurs peuvent aussi déborder, mais beaucoup plus tard. Je voudrais voir vos visages lorsque votre monde s’enroulera soudainement à -2 ^ 31 en raison d’un débordement de points fixes.

Les valeurs à virgule flottante de 64 bits ont une précision entière de 53 bits, elles sont donc vraiment précises.

rasmus
la source
Les valeurs en virgule flottante ne débordent pas réellement; si le résultat d'un calcul est trop grand pour être représenté, le résultat est un infini positif ou négatif.
Ananas
3

Dans un contexte FPS, les valeurs en points fixes peuvent en réalité constituer un passif. Une virgule flottante proche de zéro est plus précise. Ce n'est que sur de grandes distances que le point fixe devient préférable. La réponse est simplement que cela dépend du contexte.

Dans quelque chose comme une galaxie, vous pouvez utiliser des cadres de référence. Utilisez une énorme échelle pour les systèmes solaires, puis utilisez le centre du Soleil (ou un point similaire) comme point de départ pour tout ce qui se trouve à l'intérieur du système. En utilisant ce système, vous pouvez avoir votre gâteau et le manger, pour ainsi dire, et ce n'est pas difficile à imaginer.

IIRC, le développeur d'Infinity, a déclaré qu'il abordait sans cesse les problèmes d'échelle dans l'une de ses interviews.

Rushyo
la source
Il est peu probable que dans un jeu, vous ayez besoin de la précision "proche de zéro" de la virgule flottante. Si vous avez une unité d'un mètre, une précision de 10 bits vous donne une précision inférieure au millimètre et vous permet de modéliser plus de 4000 km dans chaque direction si vous êtes bloqué avec des valeurs de 32 bits. Si vous avez besoin de plus de précision qu'un millimètre, vous pouvez changer de bits, bien sûr. Passer à des valeurs 64 bits dans un jeu spatial vous donnerait un système solaire (ou plus?) Avec une précision constante sur tout le volume.
dash-tom-bang
Effectivement. Et c'est pourquoi vous utiliseriez le Soleil d'un système solaire comme point de référence dans un monde de la taille d'une galaxie! Le fait est que votre méthode choisie de gestion de la précision n'apporte rien à la table de toute façon. C'est discutable, vous pouvez donc aussi bien utiliser celui auquel votre bibliothèque / votre matériel est connecté.
Rushyo
J'ai d'ailleurs travaillé sur un jeu dans lequel nous devions modéliser plus de 4000 km dans chaque direction. Pour la compatibilité avec le code dans d'autres projets, il fallait utiliser 32 bits pour les positions. Ce n’est pas un problème théorique, étant donné les exigences commerciales imposées à la réutilisation du code et la taille des mondes de jeux actuels.
1

Si vous ne l'avez pas encore fait, vous devriez définitivement consulter le tutoriel Planet Rendering sur GameDev.net. En ce qui concerne la division de l’espace, une solution consiste à conserver deux variables de position distinctes: une macro-échelle et une micro-échelle. Cela fonctionne très bien (testé).

La solution exacte dépend de la manière dont vous envisagez de gérer les distances extrêmes dans le moteur - planifiez-vous des barrières de saut ou une compression temporelle?

Kornel Kisielewicz
la source
1

Une des raisons est que l'arithmétique en virgule flottante est "assez bonne" (ou du moins l'a été), elle produit rapidement des résultats assez précis.

Tant que vous connaissez les limites de l'arithmétique en virgule flottante et que vous modifiez vos algorithmes pour y faire face (voir la réponse de Andrew Russell), vous produirez un code qui "fonctionne".

ChrisF
la source
-1

J'écris un jeu. Dans mon jeu / programme, je dessine un vaisseau spatial à l'origine en utilisant une caméra relativement fixe et ma planète je dessine en utilisant une caméra séparée. Et ces deux choses règlent le problème pour moi, mais ma planète n’est pas encore très détaillée. En ce qui concerne la solution proposée par Andrew Russell au sujet du déplacement du monde (et je suppose que la caméra et ses habitants reviendront à l'origine), je n'essaierais vraiment pas cela si vous envisagiez de faire du jeu un jeu en réseau. Si vous déplaciez le monde sur l'application serveur en fonction des mouvements de chaque client, le monde finirait par avoir du mal à trouver un poste. Et prendrait sa position tout le temps de tout le monde jouer ce qui serait un énorme problème.

utilisateur1727819
la source