Pourquoi avez-vous besoin de float / double?


29

Je regardais http://www.joelonsoftware.com/items/2011/06/27.html et j'ai ri de la plaisanterie de Jon Skeet à propos de 0,3 et non 0,3. Personnellement, je n'ai jamais eu de problèmes avec les flotteurs / décimales / doubles mais ensuite je me souviens avoir appris 6502 très tôt et n'avais jamais eu besoin de flotteurs dans la plupart de mes programmes. La seule fois où je l'ai utilisé, c'était pour les graphiques et les mathématiques où les nombres inexacts étaient corrects et la sortie était pour l'écran et ne devait pas être stockée (dans une base de données, un fichier) ou dépendante.

Ma question est, où sont les endroits où vous utilisiez généralement des flottants / décimales / double? Je sais donc faire attention à ces accrochages. Avec de l'argent, j'utilise les longs et stocke les valeurs par cent, pour la vitesse d'un objet dans un jeu, j'ajoute des entiers et je divise (ou bitshift) la valeur pour savoir si j'ai besoin de déplacer un pixel ou non. (J'ai fait bouger un objet dans les 6502 jours, nous n'avions pas de clivage ni de flotteurs mais nous avions des décalages).

J'étais donc surtout curieux.


10
car il est très important que les intérêts que je paie sur mon hypothèque restent de 12,6 et que je devienne 13 simplement parce que 13 est un très bon chiffre rond.
Chani

1
"J'ai appris 6502 très tôt et je n'ai jamais eu besoin de flotteurs dans la plupart de mes programmes ... pour la vitesse d'un objet, j'ajoute des entiers et je divise la valeur pour savoir s'il faut déplacer un pixel ou non." Ce sont des façons très inhabituelles d'accomplir ces tâches dans la pratique moderne, à l'exception de la représentation de l'argent en cents longs.
jprete

Heureusement que l'ordinateur comprend les millicents.
tylermac

1
Ou en plus, pourquoi utiliser des décimales quand on peut utiliser des fractions?
tylermac

6
@Scrooge - ironiquement, vous ne pouvez pas représenter 0,6 dans un flotteur.
Martin Beckett

Réponses:


28

Parce qu'ils sont, dans la plupart des cas, plus précis que les entiers.

Maintenant, comment est-ce? "pour la vitesse d'un objet dans un jeu ..." c'est un bon exemple pour un tel cas. Disons que vous devez avoir des objets très rapides, comme des balles. Pour pouvoir décrire leur mouvement avec des variables de vitesse entières, vous devez vous assurer que les vitesses sont dans la plage des variables entières, ce qui signifie que vous ne pouvez pas avoir un raster arbitrairement fin.

Mais alors, vous pourriez également vouloir décrire certains objets très lents, comme l'aiguille des heures d'une horloge. Comme c'est environ 6 ordres de grandeur plus lent que les objets de balle, les premiers ld (10⁶) ≈ 20 bits sont nuls, ce qui exclut les short inttypes dès le départ. Ok, aujourd'hui nous avons des longs partout, ce qui nous laisse un 12 bits encore confortable. Mais même alors, la vitesse d'horloge sera exacte à seulement quatre décimales. Ce n'est pas une très bonne horloge ... mais c'est certainement correct pour un match. Simplement, vous ne voudriez pas rendre le raster beaucoup plus grossier qu'il ne l'est déjà.

... ce qui pose problème si un jour vous souhaitez introduire un nouveau type d'objet encore plus rapide. Il n'y a plus de "marge".

Que se passe-t-il si nous choisissons un type de flotteur? Même taille de 32 bits, mais maintenant vous avez une pleine précision de 24 bits, pour tous les objets. Cela signifie que l'horloge a suffisamment de précision pour rester synchronisée jusqu'à la seconde pendant des années. Les balles n'ont pas une précision plus élevée, mais elles ne "vivent" que pendant des fractions de seconde de toute façon, ce serait donc totalement inutile si elles l'avaient fait. Et vous ne rencontrez aucun problème si vous voulez décrire des objets encore plus rapides (pourquoi pas la vitesse de la lumière? Pas de problème) ou beaucoup plus lents. Vous n'aurez certainement pas besoin de telles choses dans un jeu, mais vous le faites parfois dans les simulations physiques.

Et avec les nombres à virgule flottante, vous obtenez toujours la même précision et sans avoir à choisir intelligemment un raster non évident. C'est peut-être le point le plus important, car ces nécessités de choix sont très sujettes aux erreurs.


Les entiers sont parfaitement précis. L'inexactitude dépend d'un calcul incorrect.
fjdumont

15
Les entiers ne sont parfaitement précis que lorsque vous les utilisez pour représenter réellement des nombres entiers (ℤ). Représenter autre chose signifie, en effet, un calcul incorrect. Dans un tel cas, vous avez deux possibilités: soit définir un type qui convient parfaitement aux nombres que vous souhaitez réellement représenter. c'est possible, par exemple Mathematica peut le faire. Mais c'est très compliqué et coûteux en temps, et ne vaut généralement pas la peine car vous n'avez pas besoin d'une précision parfaite. Mais vous avez besoin d'une bonne précision, et c'est là que les flottants font généralement un meilleur travail que les entiers.
leftaroundabout

53

Vous les utilisez lorsque vous décrivez une valeur continue plutôt qu'une valeur discrète . Ce n'est pas plus compliqué à décrire que ça. Ne faites pas l'erreur de supposer qu'une valeur avec un point décimal est continue. S'il change tout d'un coup en morceaux, comme l'ajout d'un sou, c'est discret.


28

Vous avez vraiment deux questions ici.

Pourquoi quelqu'un a-t-il besoin de mathématiques en virgule flottante, de toute façon?

Comme le souligne Karl Bielefeldt, les nombres à virgule flottante vous permettent de modéliser des quantités continues - et vous les trouvez partout - non seulement dans le monde physique, mais même dans des endroits comme les affaires et la finance.

J'ai utilisé les mathématiques à virgule flottante dans de très nombreux domaines de ma carrière en programmation: chimie, travail sur AutoCAD et même écriture d'un simulateur de Monte Carlo pour faire des prévisions financières. En fait, il y a un gars du nom de David E. Shaw qui a utilisé des techniques de modélisation scientifique basées sur virgule flottante à Wall Street pour gagner des milliards.

Et, bien sûr, il y a l'infographie. Je consulte sur le développement de bonbons pour les yeux pour les interfaces utilisateur, et essayer de le faire de nos jours sans une solide compréhension de la virgule flottante, de la trigonométrie, du calcul et de l'algèbre linéaire, serait comme se présenter à une bagarre avec un couteau de poche.

Pourquoi aurait-on besoin d'un flotteur contre un double ?

Avec les représentations standard IEEE 754, un flottant de 32 bits vous donne environ 7 chiffres décimaux de précision et des exposants compris entre 10 -38 et 10 38 . Un double 64 bits vous donne environ 15 chiffres décimaux de précision et des exposants compris entre 10 -307 et 10 307 .

Il pourrait sembler qu'un flotteur suffirait à ce dont quiconque aurait raisonnablement besoin, mais ce n'est pas le cas. Par exemple, de nombreuses quantités du monde réel sont mesurées en plus de 7 chiffres décimaux.

Mais plus subtilement, il y a un problème familièrement appelé "erreur d'arrondi". Les représentations binaires en virgule flottante ne sont valables que pour les valeurs dont les parties fractionnaires ont un dénominateur de puissance 2, comme 1/2, 1/4, 3/4, etc. Pour représenter d'autres fractions, comme 1/10, vous "arrondissez" la valeur de la fraction binaire la plus proche, mais c'est un peu faux - c'est "l'erreur d'arrondi". Ensuite, lorsque vous faites des calculs sur ces nombres inexacts, les inexactitudes dans les résultats peuvent être bien pires que celles avec lesquelles vous avez commencé - parfois les pourcentages d'erreur se multiplient, voire s'accumulent de façon exponentielle.

Quoi qu'il en soit, plus vous devez travailler avec de chiffres binaires, plus votre représentation binaire arrondie sera proche du nombre que vous essayez de représenter, donc son erreur d'arrondi sera plus petite. Ensuite, lorsque vous faites des calculs, si vous avez beaucoup de chiffres avec lesquels travailler, vous pouvez effectuer beaucoup plus d'opérations avant que l'erreur d'arrondi cumulative ne s'accumule là où c'est un problème.

En fait, les doubles 64 bits avec leurs 15 chiffres décimaux ne sont pas assez bons pour de nombreuses applications. J'utilisais des nombres à virgule flottante de 80 bits en 1985, et l'IEEE définit maintenant un type à virgule flottante de 128 bits (16 octets), pour lequel je peux imaginer des utilisations.


2
+1 Bob mon expérience avec les systèmes de contrôle à haute résolution comme le télescope pour l'astronomie est que les doubles 64 bits ne sont pas assez bons à moins que vous ne triiez vos termes. Idem pour le contrôle du tir et la navigation longue distance
Tim Williscroft

20

C'est une idée fausse commune, que partout où vous traitez avec de l'argent, vous devez stocker sa valeur sous forme d'entier (cents). Alors que dans certains cas simples comme la boutique en ligne, c'est vrai, si vous avez quelque chose de plus avancé, cela n'aide pas beaucoup.

Prenons un exemple: un développeur gagne 100 000 $ par an. Quel est son salaire mensuel exact? En utilisant un entier, vous obtenez le résultat 8333,33 $ (¢ 833333), qui multiplié par 12 est 99 999,96 $. Est-ce que le garder comme aide entière? Non, non.

Les banques utilisent-elles toujours des valeurs décimales / entières? Eh bien, ils le font pour la partie transactionnelle. Mais par exemple, dès que vous commencez à parler de banque d'investissement, à l'exception du suivi des transactions réelles, tout le reste est flottant. Comme il s'agit uniquement de code interne, vous ne le verrez pas, mais vous pouvez prendre un pic chez QuantLib , qui est essentiellement le même (sauf beaucoup plus propre ;-).

Pourquoi utiliser des flotteurs? Parce que l'utilisation de décimal n'aide pas du tout lorsque vous utilisez des fonctions comme la racine carrée, les logarithmes, les pouvoirs avec des exposants non entiers, etc. Et bien sûr, les flottants sont beaucoup plus rapides que les types décimaux.


1
@Job - les décimales et les flottants sont très différents. Vous pouvez stocker 0,1 exactement dans un type décimal, mais pas dans un flottant ou double.
Scott Whitlock

3
J'avais une autre question. Si vous avez payé $100,000/12et utilisé un flotteur. Pourquoi le résultat serait-il exactement de 100 000 $? Pourquoi le flottant (ou le nombre décimal) ne serait-il pas arrondi à la hausse ou à la baisse à chaque fois que quelqu'un est payé? Je parle lors de la rédaction d'un chèque (vous ne pouvez pas faire 1/2 ou 1/3 centime) ou d'un dépôt direct (je suppose qu'il a les mêmes limites)

@acid: >>> x = 100000 / 12,0 >>> x * 12 100000,0
vartec

relire mon commentaire? ma question est quand j'utilise un logiciel pour créer un chèque chaque mois. Puisqu'on ne peut pas payer 1/2 centime, comment la personne obtient-elle le plein montant après un an?

2
@acid: vous ne pouvez pas utiliser la division droite, que vous utilisiez un entier, un décimal ou une division comme flottant puis arrondi. C'est tout l'intérêt, l'utilisation de la décimale n'aide pas dans ce cas.
vartec

4

Ce que vous avez décrit est un excellent moyen de contourner les situations dans lesquelles vous contrôlez toutes les entrées et sorties .

Dans le vrai mot, ce n'est pas le cas. Vous devrez être en mesure de faire face aux systèmes qui vous fournissent leurs données sous forme de valeur réelle avec un certain degré de précision et vous attendez à ce que vous renvoyiez les données dans le même format. Dans ce cas , vous allez rencontrer ces problèmes.

En fait, vous rencontrerez ces problèmes même si vous utilisez les astuces que vous listez. Lors du calcul de la taxe de 17,5% sur un prix, vous obtiendrez des cents fractionnaires, que vous stockiez la valeur en dollars ou en cents. Il faut que l'arrondissement soit correct, car le contribuable est très contrarié si vous ne le payez pas suffisamment. Utiliser les bons moneytypes (quel qu'ils soient dans la langue que vous utilisez) vous sauvera d'un monde de douleur.


Quel est le type d'argent? (langue ou lien de référence) et pourquoi est-ce le type «correct»? Est-ce parce que c'est ... 128 bits ou plus? Mon autre pourquoi l'utilisation de mes «astuces» serait-elle incorrecte? Vous avez un nombre entier en centimes. Si vous le multipliez par 0,175, vous obtiendrez un nombre entier et l'utiliserez pour tout ce que vous voulez. En pensant à votre exemple, je pense que float serait capable de contenir ma valeur avec suffisamment de précision, mais je n'aurai pas à me soucier du fait que 0.3f == 0.3d soit faux. -edit- et +1

1
@ acidzombie24 - Je ne voulais pas dire un type spécifique, mais quel type de texte votre langue utilise pour représenter les valeurs monétaires. De plus, si vous avez 10 cents et que vous multipliez par 0,175, vous avez 1,75 cents - comment gérez-vous cela avec l'arithmétique entière? Est-ce 1 cent ou 2 cents? Se tromper et votre client pourrait finir par posséder le fisc beaucoup d'argent.
ChrisF

Vous ne devez jamais multiplier 10 (un entier) par 0,175 (un nombre réel / flottant) car vous ne devez pas mélanger des nombres exacts avec des nombres inexacts; le résultat sera inexact. En d'autres termes, dans un système de nombres exacts, une valeur comme 0,175 n'existerait jamais, et c'est donc un calcul non sensible. Une meilleure solution consiste à multiplier 10000 par 175 et à insérer manuellement un point décimal, le cas échéant.
Barry Brown

8
@Barry - Je sais. J'essayais d'illustrer le type de problème que vous rencontrez. Il existe également une valeur comme 0,175 si le taux de taxe est de 17,5% et que vous devez calculer la taxe sur un article qui coûte 10 cents.
ChrisF

1
@acidzombie: Le type correct à utiliser pour l'argent est une décimale à virgule fixe avec une précision élevée (au moins 4 décimales). Pas de si, de et, ou de mais. Stocker des valeurs monétaires en cents n'est pas suffisant, car en pratique, cela ne vous donne que deux points de précision.
Aaronaught

3

"Dieu a créé les nombres entiers, tout le reste est l'œuvre de l'homme." - Léopold Kronecker (1886).

Par définition, vous n'avez pas besoin d'autres types de numéros. L'intégralité de Turing pour un langage de programmation est basée sur les relations simples entre les différents types de nombres. Si vous pouvez travailler avec des nombres entiers (a / k / a nombres naturels), vous pouvez tout faire.

La question est un peu spécieuse car vous n'en avez pas besoin . Peut-être que vous voulez des endroits où c'est pratique ou optimal ou moins cher ou quelque chose?


7
Nous pouvons également nous passer de nombres entiers, car on peut également les construire en utilisant uniquement des opérations de théorie des ensembles et l'ensemble vide. Mais à la fois cela et l'argument de l'exhaustivité de Turing sont un réductionnisme académique poussé à l'extrême.
Bob Murphy

4
De plus, l'intégralité de Turing ne s'applique qu'à l'informatique. Ni les nombres entiers ni même les rationnels ne sont mathématiquement complets, car aucun n'est fermé à la convergence des séquences de Cauchy. Donc Kronecker était plein d'air chaud: si vous voulez un espace métrique complet qui inclut les nombres entiers, vous devez être réel: xkcd.com/849
Bob Murphy

1
@Bob Murphy: "le réductionnisme académique poussé à l'extrême". Précisément. La question est médiocre et mène à cela comme réponse possible.
S.Lott

2

Dans une phrase, les types décimaux à virgule flottante encapsulent la conversion vers et à partir de valeurs entières (c'est tout ce que l'ordinateur sait gérer au niveau binaire; il n'y a pas de point décimal en binaire) fournissant une logique, généralement facile à comprendre l'interface pour le calcul des nombres décimaux.

Franchement, dire que vous n'avez pas besoin de flottants parce que vous savez comment faire des mathématiques décimales en utilisant des entiers, c'est comme dire que vous savez comment faire de l'arithmétique à la main, alors pourquoi utiliser une calculatrice? Vous connaissez donc le concept; Bravo. Cela ne signifie pas que vous devez exercer cette connaissance tout le temps. Il est souvent plus rapide, moins cher et plus compréhensible pour un non-binaire de dire simplement 3,5 + 4,6 = 8,1 plutôt que de convertir les figues sig en une quantité entière.


1

Le principal avantage des types à virgule flottante est que du point de vue de l'exécution, deux ou trois formats (je souhaite que davantage de langues prennent en charge les formats 80 bits) suffiront pour la majorité rapide des fins de calcul. Si les langages de programmation pouvaient facilement prendre en charge une famille de types à virgule fixe, la complexité matérielle requise pour un niveau de performance donné serait souvent plus faible avec les types à virgule fixe qu'avec la virgule flottante. Malheureusement, fournir un tel soutien est loin d'être "facile".

Pour qu'un langage de programmation satisfasse efficacement 98% des besoins numériques des applications, il devrait inclure des dizaines de types et fournir des opérations de définition pour des centaines de combinaisons; en outre, même si un langage de programmation avait une excellente prise en charge des virgules fixes, certaines applications auraient encore besoin de maintenir une précision relative à peu près constante sur une plage suffisamment large pour nécessiter des virgules flottantes. Étant donné que les maths à virgule flottante seront nécessaires à certaines occasions dans tous les cas, faire en sorte que les fournisseurs de matériel se concentrent sur les performances mathématiques avec deux ou trois formats à virgule flottante, et que le code utilise ces formats chaque fois qu'ils fonctionnent raisonnablement bien, permettra généralement d'obtenir de meilleurs résultats. "en avoir pour son argent" que d'essayer d'optimiser le comportement des mathématiques à virgule fixe.

Par ailleurs, les mathématiques en virgule fixe étaient plus avantageuses avec les processeurs 8 bits et 16 bits qu'avec les processeurs 32 bits. Sur un processeur 8 bits, dans une situation où 32 bits ne suffirait pas tout à fait, un type 40 bits ne coûterait que 25% d'espace en plus et 25 à 50% plus de temps que le type 32 bits, et nécessiterait 37,5% moins d'espace et 37,5 à 60% moins de temps qu'un type 64 bits. Sur une plate-forme 32 bits, si un type 32 bits ne suffit pas, il y a souvent peu de raisons d'utiliser moins de 64 bits. Si un type à virgule fixe de 48 bits était suffisant, un "double" de 64 bits fonctionnerait aussi bien que le type à virgule fixe.


0

En règle générale, vous devez être très prudent de les utiliser. Comprendre la perte de précision qui peut résulter de calculs même simples est un défi. Par exemple, la moyenne d'une liste de nombres comme celle-ci est une très mauvaise idée:

double average(List<Double> data) {
  double ans = 0;
  for(Double d : data) {
    ans += d;
  }
  return ans / data.size();
}

La raison en est que, pour des listes suffisamment volumineuses, vous perdez essentiellement tous les points de données lorsqu'ils anssont suffisamment volumineux (voir par exemple ceci ). Le problème avec ce code est que pour les petites listes, cela fonctionnera probablement - ce n'est qu'à l'échelle qu'il casse.

Personnellement, je pense que vous ne devriez les utiliser que lorsque: a) le calcul doit vraiment être rapide; b) vous ne vous souciez pas que le résultat soit susceptible d'être éloigné (à moins que vous ne sachiez vraiment ce que vous faites).


-1

Une pensée est que vous utiliseriez les représentations flottantes ou doubles lorsque vous avez besoin de traiter des valeurs en dehors de la plage entière.

Les architectures actuelles (grosso modo) ont une plage d'entiers signés de +/- 2.147.483.647 (32 bits) ou +/- 9.223.372.036.854.775.807 (64 bits). Non signé prolonge cela d'un facteur 2.

Les flotteurs IEEE 754 (grossièrement) passent de +/- 1,4 × 10 ^ −45 à 3,4 × 10 ^ 38. Double étend cette plage à +/- 5 × 10−324 ± 2.225 × 10 ^ −308 avec de nombreuses conditions et spécificités omises ici.

Bien sûr, la raison la plus évidente est que vous devrez peut-être représenter -0 ;-)


Les chiffres proviennent principalement d'articles de Wikipédia et sont destinés à être illustratifs. Sauf -0, c'est juste pour le plaisir.
Stephen

Le problème est qu'il y a BEAUCOUP d'entiers dans cette immense plage qui ne sont pas du tout représentés.
Barry Brown

@BarryBrown Absolument raison. "beaucoup de conditions et de détails omis" cependant.
Stephen

-1

La raison habituelle est qu'ils sont rapides car la JVM utilise généralement le support matériel sous-jacent (sauf si vous utilisez strictfp).

Voir https://stackoverflow.com/questions/517915/when-to-use-strictfp-keyword-in-java pour ce que strictfp implique.


Les mathématiques en virgule flottante sont plus rapides que les mathématiques entières? Sur quel processeur les calculs en virgule flottante prennent-ils moins de cycles que les calculs entiers?
this.josh

1
@ this.josh, dépend fortement du nombre de chiffres que vous avez dans vos numéros. De plus, les entiers ne peuvent pas diviser précisément ce qui peut ou non être important.

-2

C'est pourquoi nous avons besoin de systèmes d'exploitation 256 bits.

La longueur de la planche (la plus petite distance que vous pouvez mesurer) = 10 ^ -35m
L'univers observable est de 14 milliards de parsecs sur = 10 ^ 25m
Vous pouvez donc mesurer n'importe quoi en unités de la longueur de la planche sous forme d'entiers si vous n'avez que 200 bits de précision.


2
-1: et si vous simulez des choses à une échelle plus grande que l'univers observable?
amara

2
@sparkleshy, c'est à ça que servent les pointeurs FAR!
Martin Beckett
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.