Pourquoi les ordinateurs ne stockent-ils pas des nombres décimaux comme deuxième nombre entier?

24

Les ordinateurs ont du mal à stocker des nombres fractionnaires où le dénominateur est autre chose qu'une solution à 2 ^ x. En effet, le premier chiffre après la décimale vaut 1/2, le deuxième 1/4 (ou 1 / (2 ^ 1) et 1 / (2 ^ 2)) etc.

Pourquoi traiter toutes sortes d'erreurs d'arrondi alors que l'ordinateur aurait pu simplement stocker la partie décimale du nombre comme un autre nombre entier (ce qui est donc exact?)

La seule chose à laquelle je peux penser est la répétition des décimales (en base 10), mais il aurait pu y avoir une solution de bord (comme nous l'avons actuellement avec l'infini).

SomeKittens
la source
8
Vous devriez rechercher comment les types décimaux sont stockés, contrairement aux types float / double.
Odé
9
Je ne sais pas comment c'est plus précis. Le premier chiffre après la décimale est 1/10 le deuxième 1/100 etc. Comment est-ce plus précis que vous rencontrez toujours des problèmes d'arrondi (comment représentez-vous 1/3)? La seule différence est quelles valeurs peuvent être représentées exactement.
Martin York
17
La virgule flottante décimale (ce à quoi vous faites référence deux, juste dans une représentation plus maladroite) n'est pas plus inexacte que la virgule flottante binaire. La seule différence est quelles valeurs ne peuvent pas être représentées, et parce que nous sommes habitués au système décimal, nous ne remarquons pas les erreurs de la version décimale. Et non, aucun ne peut représenter tous les nombres rationnels et irrationnels.
1
En fin de compte, cela se résume à l'efficacité. Les ordinateurs sont binaires et les circuits pour travailler avec cette représentation binaire sont beaucoup moins complexes. L'importance de cela peut être quelque peu diminuée aujourd'hui, mais il fut un temps où cela était très important. De plus, toute représentation que vous choisissez de stocker votre numéro (dans un espace fini) sur un ordinateur aura un ensemble fini de valeurs qu'il peut représenter et tous présenteront des erreurs d'arrondi avec certaines entrées. Le format à virgule flottante typique avec Mantissa et Exponent offre une plage beaucoup plus grande qu'il serait alors possible d'utiliser deux entiers.
Mr.Mindor
1
Je recommanderais fortement de lire certains des articles référencés dans ma réponse à la question Quelles sont les causes des erreurs d'arrondi à virgule flottante? que je viens de mettre à jour avec les détails du dernier article de la série référencée. En particulier, jetez un œil à Pourquoi le point fixe ne guérira pas vos bleus à virgule flottante .
Mark Booth

Réponses:

35

Il existe en fait des modes de nombres qui font cela.

L'arithmétique décimale codée binaire (BCD) a le travail informatique en base 10. La raison pour laquelle vous rencontrez rarement cela est qu'il gaspille de l'espace: chaque chiffre individuel d'un nombre prend au moins quatre bits, alors qu'un ordinateur pourrait autrement stocker jusqu'à 16 valeurs dans cet espace. (Il peut également être plus lent, mais il est possible d'avoir des calculs BCD accélérés par le matériel qui fonctionnent très bien.). C'est, en fait, exactement ce que font la plupart des calculatrices, c'est pourquoi il existe certaines classes de problèmes d'arrondi que vous ne rencontrerez jamais sur un Casio à 5 $ qui mangera votre déjeuner sur un ordinateur de bureau.

L'autre voie que vous pouvez emprunter est d'utiliser des nombres rationnels, c'est-à-dire un numérateur et un dénominateur, stockés sous forme d'entiers. Il est en fait disponible dans presque toutes les langues, est exact et vous permet de tout stocker dans des formats binaires natifs. Le problème est qu'en fin de compte, les utilisateurs ne veulent probablement pas voir des fractions comme 463/13, ni même 35 et 8/13. Ils veulent voir 35.615 ..., et au moment où vous y arrivez, vous êtes confronté à tous les problèmes typiques. Ajoutez que ce format prend encore plus d' espace et peut être beaucoup plus lent que l'arithmétique à virgule flottante, et vous ne trouverez aucun ordinateur utilisant ce format par défaut.

Donc: les ordinateurs peuvent faire ce que vous voulez, mais c'est lent et cela gaspille de l'espace, donc ils ne le font que lorsqu'ils en ont vraiment besoin. Le reste du temps, la vitesse et les économies d'espace de la virgule flottante sont un meilleur compromis.

Benjamin Pollack
la source
Ne voulez-vous pas dire quatre bits (pas d'octets) dans le paragraphe BCD?
3
L'autre option est l'arithmétique à virgule fixe, où un entier représente une fraction décimale si un nombre - par exemple, le stockage des valeurs monétaires (sans calculs impliquant des décimales ou un pourcentage) où 1 représente 0,01 $.
mattnz
1
@mattnz: Vrai - les points fixes sont un cas particulier de rationalités.
Jon Purdy
Génial, je ne savais pas que les calculatrices faisaient ça.
SomeKittens
3
Il existe une troisième option. Virgule flottante avec un exposant décimal, comme la façon dont C # decimalest implémenté: stackoverflow.com/a/5019178/174335 Ce n'est pas BCD car il n'y a pas de représentation individuelle des chiffres décimaux et ce n'est pas un point fixe.
Joren
38

Il existe de nombreuses façons de stocker des nombres fractionnaires, et chacun d'eux présente des avantages et des inconvénients.

La virgule flottante est, de loin, le format le plus populaire. Il fonctionne en codant un signe, une mantisse et un exposant de base 2 signé en entiers, et en les regroupant en un tas de bits. Par exemple, vous pourriez avoir une mantisse 32 bits de 0.5(codé comme 0x88888888) et un exposant signé 32 bits de +3( 0x00000003), qui décoderait en 4.0(0.5 * 2 ^ 3). Les nombres à virgule flottante sont rapides, car ils sont implémentés dans le matériel et leurs échelles de précision avec une taille absolue, c'est-à-dire que plus le nombre est petit, meilleure est votre précision absolue, de sorte que l'erreur d'arrondi relative reste constante avec la taille absolue. Les flotteurs sont excellents pour les valeurs échantillonnées à partir d'un domaine continu, telles que les longueurs, les niveaux de pression acoustique, les niveaux de lumière, etc., et pour cette raison, ils sont couramment utilisés dans le traitement audio et d'image, ainsi que dans l'analyse statistique et les simulations physiques. Leur plus gros inconvénient est qu'ils ne sont pas exacts, c'est-à-dire qu'ils sont sujets à des erreurs d'arrondi et qu'ils ne peuvent pas représenter avec précision toutes les fractions décimales. Tous les langages de programmation traditionnels ont une sorte de flotteur.

Un point fixefonctionne en utilisant des entiers suffisamment grands et en réservant implicitement une partie de leurs bits pour la partie fractionnaire. Par exemple, un nombre à virgule fixe de 24,8 bits réserve 24 bits pour la partie entière (signe compris) et 8 bits pour la partie fractionnaire. Décaler ce nombre de 8 bits vers la droite nous donne la partie entière. Les nombres à virgule fixe étaient populaires lorsque les unités matérielles à virgule flottante étaient rares ou au moins beaucoup plus lentes que leurs homologues entiers. Bien que les nombres à virgule fixe soient un peu plus faciles à gérer en termes d'exactitude (ne serait-ce que parce qu'ils sont plus faciles à raisonner), ils sont inférieurs aux flottants à presque tous les autres égards - ils ont moins de précision, une plage plus petite et parce que plus des opérations sont nécessaires pour corriger les calculs du décalage implicite, les mathématiques à virgule fixe sont aujourd'hui souvent plus lentes que les mathématiques à virgule flottante.

Les types décimaux fonctionnent un peu comme des flottants ou des nombres à virgule fixe, mais ils supposent un système décimal, c'est-à-dire que leur exposant (implicite ou explicite) code la puissance de 10, pas la puissance de 2. Un nombre décimal pourrait, par exemple, coder une mantisse de 23456et un exposant de -2, et cela s'élargirait à234.56. Les décimales, parce que l'arithmétique n'est pas câblée dans le CPU, sont plus lentes que les flottants, mais elles sont idéales pour tout ce qui implique des nombres décimaux et a besoin que ces nombres soient exacts, avec l'arrondi se produisant à des endroits bien définis - calculs financiers, tableaux de bord, etc. Certains langages de programmation ont des types décimaux intégrés (par exemple C #), d'autres nécessitent des bibliothèques pour les implémenter. Notez que si les décimales peuvent représenter avec précision des fractions décimales non répétitives, leur précision n'est pas meilleure que celle des nombres à virgule flottante; choisir des décimales signifie simplement que vous obtenez des représentations exactes de nombres qui peuvent être représentés exactement dans un système décimal (tout comme les flottants peuvent représenter exactement des fractions binaires).

Les nombres rationnels stockent un numérateur et un dénumérateur, en utilisant généralement une sorte de type entier bignum (un type numérique qui peut augmenter aussi grand que le permettent les contraintes de mémoire de l'ordinateur). C'est le seul type de données du groupe qui peut modéliser avec précision des nombres comme 1/3ou 3/17, ainsi que des opérations sur eux - les rationnels, contrairement aux autres types de données, produiront des résultats corrects pour des choses comme3 * 1/3. Les calculs sont assez simples, bien que trouver un algorithme de factorisation efficace soit plutôt difficile. Certains langages de programmation ont des types rationnels intégrés (par exemple Common Lisp). Les inconvénients des rationnels incluent qu'ils sont lents (de nombreuses opérations nécessitent de réduire les fractions et de factoriser leurs composants), et que de nombreuses opérations courantes sont difficiles ou impossibles à implémenter, et la plupart des implémentations dégraderont le rationnel en flottant lorsque cela se produira (par exemple lorsque vous appelez sin()sur un rationnel).

BCD (Binary Coded Decimal) utilise des "quartets" (groupes de 4 bits) pour coder des chiffres individuels; comme un quartet peut contenir 16 valeurs différentes, mais que les nombres décimaux ne nécessitent que 10, il y a 6 valeurs "illégales" par quartet. Comme les décimales, les nombres BCD sont exacts en décimales, c'est-à-dire que les calculs effectués sur les nombres décimaux fonctionnent comme s'ils le faisaient avec un stylo et du papier. Les règles arithmétiques pour BCD sont quelque peu maladroites, mais l'avantage est que les convertir en chaînes est plus facile qu'avec certains autres formats, ce qui est particulièrement intéressant pour les environnements à faibles ressources comme les systèmes embarqués.

Les chaînes , oui, les vieilles chaînes simples, peuvent également être utilisées pour représenter des nombres fractionnaires. Techniquement, c'est très similaire à BCD, seulement qu'il y a un point décimal explicite et que vous utilisez un octet complet par chiffre décimal. En tant que tel, le format est inutile (seulement 11 des 256 valeurs possibles sont utilisées), mais il est plus facile à analyser et à générer que BCD. De plus, comme toutes les valeurs utilisées sont "peu suspectes", inoffensives et neutres sur la plate-forme, les nombres codés en chaîne peuvent voyager sans problème sur les réseaux. Il est rare de trouver des calculs arithmétiques directement sur les chaînes, mais c'est possible, et lorsque vous le faites, ils sont tout aussi décimaux que les autres formats décimaux (décimaux et BCD).

tdammers
la source
Le point fixe 32 bits a certainement plus de précision que le point flottant 32 bits, car les représentations en point fixe n'incluent pas de mantisse.
han
4
@han: dépend de la taille du numéro que vous souhaitez stocker. Les flotteurs vous donneront (à peu près) la même précision, peu importe la taille du nombre, tandis que le point fixe ne vous donnera une précision complète que si le nombre que vous souhaitez stocker s'intègre parfaitement dans sa plage.
Leo
@han Pas nécessairement, les deux peuvent toujours représenter 2 ^ 32 valeurs distinctes. La quantité d'informations transportées est identique, quelle que soit la présentation. La plage et la précision vont de pair, donc à cet égard, l'arithmétique à virgule fixe peut être plus précise dans certaines plages. Et évite les problèmes d'arrondi aléatoires désagréables, si vous connaissez les limites dans lesquelles vous pouvez travailler.
zxcdw
@han: ils ont la même précision (ou presque). La différence est que pour les nombres à virgule fixe, la précision (comme dans la taille d'un pas discret d'un nombre à son successeur) est constante, tout comme avec les nombres entiers, tandis qu'avec les flottants, elle croît de façon à peu près linéaire avec la valeur absolue - le flotteur le nombre 1.0 a plus de précision que le nombre 10 000 000,0 (un million de fois plus, grosso modo).
tdammers
6

Les nombres à virgule flottante représentent une vaste gamme de valeurs, ce qui est très utile lorsque vous ne savez pas à l'avance quelles pourraient être les valeurs, mais c'est un compromis. Représenter 1/10 ^ 100 avec un deuxième entier ne fonctionnerait pas.

Certaines langues (et certaines bibliothèques) ont d'autres caractéristiques. Lisp a traditionnellement des entiers de précision infinie. Cobol a des calculs avec des nombres décimaux à virgule fixe.

Vous devez sélectionner votre représentation numérique appropriée au domaine problématique.

ddyer
la source
1

Il semble que vous décriviez des nombres à virgule fixe .

Gardez à l'esprit que le stockage de la partie fractionnaire d'un nombre dans un emplacement séparé est exactement identique à la création d'un espace unique, deux fois plus long, et au stockage de la partie entière et fractionnaire dans les deux moitiés séparées. En d'autres termes, cela revient à stocker le nombre sous forme d'entier mais simplement à supposer un nombre fixe d'espaces décimaux.

Normalement, les nombres à virgule flottante sont stockés à l'aide d'une variation binaire de la notation scientifique, car ce qui compte généralement, ce sont les chiffres significatifs. De nombreuses autres méthodes existent cependant. Les nombres décimaux à virgule fixe sont couramment utilisés par exemple pour stocker des valeurs monétaires, où la précision est critique jusqu'à un certain nombre entier de décimales mais le nombre de chiffres décimaux requis ne change jamais.

tylerl
la source
1

Cela s'appellerait BCD, je pense que vous pouvez toujours l'utiliser si vous le voulez vraiment. Mais ça ne vaut pas vraiment le coup car:

  1. Vous rencontrerez très rarement une erreur d'arrondi avec virgule flottante 64 bits
  2. Il rend le complexe arithmatique et inefficace
  3. Il gaspille 6 valeurs tous les 4 bits
Lama inversé
la source
Le calcul BCD a été beaucoup utilisé sur les premiers systèmes de microprocesseur 8 bits; en effet, sur un microprocesseur populaire (le 6502), l'addition et la soustraction avec BCD sont tout aussi rapides par octet qu'avec binaire. Les jeux vidéo utilisaient fréquemment les mathématiques BCD pour la tenue des scores. Il n'y a pas de traitement spécial pour le regroupement des scores à 1 000 000 de points. Au lieu de cela, l'ajout de 1 à "99 99 99" donne "00 00 00" avec un report qui est ignoré. Le surcoût supplémentaire lié à l'ajout de scores à BCD est minime par rapport au coût de conversion d'une valeur binaire en format affichable.
supercat
1

La réponse courte est que la virgule flottante a été conçue pour des calculs scientifiques. Il peut stocker un nombre avec (jusqu'à) un nombre spécifié de chiffres significatifs, ce qui correspond étroitement à la façon dont la précision est mesurée dans la plupart des calculs scientifiques.

Cela a tendance à être pris en charge par le matériel, en grande partie parce que les calculs scientifiques ont tendance à être ceux qui ont le plus bénéficié du support matériel. Par exemple, les calculs financiers sont souvent effectués avec d'autres formats - mais les logiciels financiers font généralement assez peu de calculs réels que même si les formats nécessaires ne sont pris en charge que par les logiciels, les performances restent parfaitement adéquates pour la plupart des logiciels financiers.

Jerry Coffin
la source