Pourquoi pas des nombres décimaux être représenté exactement en binaire?

il y a eu plusieurs questions sur la représentation en virgule flottante. Par exemple, le nombre décimal 0.1 n'est pas une représentation binaire exacte, il est donc dangereux d'utiliser l'opérateur == pour comparer à un autre nombre à virgule flottante. Je comprends les principes derrière représentation à virgule flottante.

ce que je ne comprends pas est pourquoi, d'un point de vue mathématique, sont les nombres à la droite du point décimal plus " spécial" que ceux de la gauche?

par exemple, le nombre 61.0 a une représentation binaire exacte parce que la partie intégrale de n'importe quel nombre est toujours exacte. Mais le nombre 6.10 n'est pas exact. Tout ce que j'ai fait c'est déplacer la première décimale et soudainement je suis passé D'Exactopia à Inexactville. Mathématiquement, il ne devrait pas y avoir de différence intrinsèque entre les deux nombres -- ce ne sont que des nombres.

par contre, si je déplace la décimale une place dans l'autre direction pour produire le numéro 610, je suis toujours à Exactopia. Je peux continuer dans cette direction (6100, 610000000, 610000000000000) et ils sont toujours exacts, exacts. Mais dès que la décimale franchit un certain seuil, les nombres ne sont plus exacts.

que se passe-t-il?

Edit: pour clarifier, je veux rester à l'écart de la discussion sur les représentations standard de l'industrie, comme L'IEEE, et s'en tenir à ce que je crois être la voie mathématique "pure". En base 10, les valeurs de position sont:

... 1000  100   10    1   1/10  1/100 ...

En binaire, ils seraient:

... 8    4    2    1    1/2  1/4  1/8 ...

il n'y a pas non plus de limites arbitraires à ces nombres. Les positions s'accroître indéfiniment vers la gauche et vers la droite.

259
demandé sur Barry Brown 2009-07-07 00:17:12

20 réponses

les nombres Décimaux peut être représentée exactement, si vous avez suffisamment d'espace - juste pas par flottante binaire les nombres à virgule. Si vous utilisez un flottant décimal de type de point (par exemple System.Decimal dans .NET) alors beaucoup de valeurs qui ne peuvent pas être représentées exactement en virgule flottante binaire peuvent être exactement représentées.

regardons cela d'une autre façon-dans la base 10 que vous êtes susceptible d'être confortable avec, vous ne pouvez pas exprimer 1/3 exactement. C'est 0.3333333... (récurrent.) La raison pour laquelle vous ne pouvez pas représenter 0.1 comme un nombre flottant binaire est exactement la même raison. Vous pouvez représenter 3, et 9, et 27 exactement - mais pas 1/3, 1/9 ou 1/27.

Le problème est que 3 est un nombre premier qui n'est pas un facteur de 10. Ce n'est pas un problème quand vous voulez multiplier un nombre par 3: vous pouvez toujours multiplier par un entier sans rencontrer de problèmes. Mais quand vous divisez par un nombre qui est premier et n'est pas un facteur de votre base, vous pouvez courir dans l'ennui (et will si vous essayez de diviser 1 par ce nombre).

bien que 0,1 soit habituellement utilisé comme l'exemple le plus simple d'un nombre décimal exact qui ne peut pas être représenté exactement en virgule flottante binaire, sans doute 0,2 est un exemple plus simple car il est 1/5 - et 5 est le premier qui provoque des problèmes entre décimal et binaire.


note de Côté pour faire face au problème de finis représentations:

certains types de virgule flottante ont une taille fixe comme System.Decimal d'autres comme java.math.BigDecimal sont "arbitrairement grands" - mais ils vont frapper une limite à un point, que ce soit la mémoire du système ou la taille maximale théorique d'un tableau. C'est tout à fait distincts pour le principal de cette réponse, cependant. Même si vous avez eu un véritable arbitrairement grand nombre de bits pour jouer avec, vous ne pouviez pas encore représenter décimal 0.1 exactement dans une représentation binaire flottante de point. Comparez cela avec l'inverse: étant donné un nombre arbitraire de chiffres décimaux, vous peut représentent exactement n'importe quel nombre qui est exactement représentatif comme un point binaire flottant.

335
répondu Jon Skeet 2009-07-06 21:33:29

la raison de cette imprécision est la nature des bases numériques. En base 10, vous ne pouvez pas représenter exactement 1/3. Il devient 0.333... Cependant, en base 3, 1/3 est exactement représenté par 0.1 et 1/2 est une décimale à répétition infinie (trésimal?). Les valeurs qui peuvent être finement représentées dépendent du nombre de facteurs premiers uniques de la base, donc la base 30 [2 * 3 * 5] peut représenter plus de fractions que la base 2 ou la base 10. Encore plus pour la base 210 [2 * 3 * 5 * 7].

C'est une question distincte de la "virgule flottante erreur". L'inexactitude est due au fait que quelques milliards de valeurs sont réparties sur une fourchette beaucoup plus large. Donc, si vous avez 23 bits pour le significand, vous ne pouvez représenter qu'environ 8,3 millions de valeurs distinctes. Puis un exposant 8 bits fournit 256 options pour distribuer ces valeurs. Ce schéma permet aux décimales les plus précises de se produire près de 0, de sorte que vous pouvez presque représentent 0,1.

30
répondu James M. 2009-07-06 21:59:20

par exemple, le nombre 61.0 a une représentation binaire exacte parce que la partie intégrale de n'importe quel nombre est toujours exacte. Mais le nombre 6.10 n'est pas exact. Tout ce que j'ai fait c'est déplacer la première décimale et soudainement je suis passé D'Exactopia à Inexactville. mathématiquement, il ne devrait pas y avoir de différence intrinsèque entre les deux nombres -- ce sont juste des nombres .

éloignons-nous un instant de les détails des bases 10 et 2. Posons la question à la base b , quels nombres ont des représentations terminales, et quels nombres n'en ont pas? La pensée d'un moment nous dit qu'un nombre x a une représentation finale b si et seulement s'il existe un entier n tel que x b^n est un entier.

ainsi ,par exemple, x = 11/500 a une terminaison 10-représentation , parce que nous pouvons choisir n = 3 et puis x b^n = 22 , un entier. Cependant x = 1/3 ne le fait pas, parce que quoi que n nous choisissons nous ne serons pas en mesure de se débarrasser de la 3.

ce second exemple nous amène à réfléchir sur les facteurs, et nous pouvons voir que pour n'importe quel rationnel" 1519450920 x = p/q (supposé être dans les termes les plus bas), nous pouvons répondre à la question en comparant les principales factorisations de b et q . Si q a n'importe quels facteurs principaux non dans la première factorisation de b , nous ne serons jamais en mesure de trouver un n pour se débarrasser de ces facteurs.

donc pour la base 10, toute p/qq a des facteurs principaux autres que 2 ou 5 n'aura pas de représentation finale.

donc en revenant maintenant aux bases 10 et 2, nous voyons que n'importe quel rationnel avec une terminaison 10-représentation sera de la forme p/q exactement quand q a seulement 2 s et 5 s dans sa première factorisation; et ce même nombre aura une terminaison 2-representation exactement quand q a seulement 2 s dans sa première factorisation.

Mais un de ces cas est un sous-ensemble de l'autre! Quand

q n'a que 2 s dans sa principale factorisation

c'est évidemment aussi vrai que

q n'a que 2 s et 5 s dans sa principale factorisation

ou, autrement dit, chaque fois que p/q a une terminaison de 2-représentation p/q a une terminaison de 10-représentation . L'inverse ne pas tenir-chaque fois que q a un 5 dans sa principale factorisation, il sera ont un 10-représentation de fin , mais pas une 2-Représentation de fin. C'est l'exemple 0.1 mentionné par d'autres réponses.

nous avons donc la réponse à votre question - parce que les facteurs premiers de 2 sont un sous-ensemble des facteurs premiers de 10, tous les 2-terminants sont des nombres terminants de 10, mais pas l'inverse. il ne s'agit pas de 61 contre 6,1 - il s'agit de 10 contre 2.

en guise de conclusion, Si par certains gens excentriques ont utilisé (disons) la base 17 Mais que nos ordinateurs ont utilisé la base 5, votre intuition n'aurait jamais été détournée par ceci - il y aurait eu Non (non-zéro, non-entier) nombres qui se sont terminés dans les deux cas!

21
répondu AakashM 2009-07-08 21:33:26

la raison fondamentale (mathématique) est que lorsque vous avez affaire à des entiers, ils sont councily infinite .

ce qui signifie que, même s'il y en a une infinité, nous pourrions" compter " tous les éléments de la séquence, sans en Sauter aucun. Cela signifie que si nous voulons obtenir l'article dans la 610000000000000 ème position dans la liste, on peut le découvrir par l'intermédiaire d'une formule.

Cependant, les nombres réels sont uncounctably infinite . Vous ne pouvez pas dire "Donnez-moi le vrai numéro au poste 610000000000000 " et obtenir une réponse. La raison en est que, même entre 0 et 1 , il y a un nombre infini de valeurs, lorsque vous considérez des valeurs à virgule flottante. Il en va de même pour deux nombres à virgule flottante.

plus d'informations:

http://en.wikipedia.org/wiki/Countable_set

http://en.wikipedia.org/wiki/Uncountable_set

mise à Jour: Excusez-moi, j'ai mal interprété la question. Ma réponse est sur la raison pour laquelle nous ne pouvons pas représenter chaque réelle valeur, je n'avais pas réalisé que la virgule flottante a été automatiquement classé comme rationnel.

15
répondu TM. 2009-07-06 20:45:12

pour répéter ce que j'ai dit dans mon commentaire à M. Skeet: nous can représentent 1/3, 1/9, 1/27, ou n'importe quel rationnel en notation décimale. Nous le faisons en ajoutant un symbole supplémentaire. Par exemple, une ligne au-dessus des chiffres qui répètent dans l'expansion décimale du nombre. Ce que nous devons représenter des nombres décimaux comme une séquence de nombres binaires sont 1) une séquence de nombres binaires, 2) un point radix, et 3) un autre symbole pour indiquer la partie répétitive de la séquence.

dans le hehner citation de notation est une façon de le faire. Il utilise un symbole de citation pour représenter la partie répétitive de la séquence. L'article: http://www.cs.toronto.edu hehner ratno.pdf et L'entrée Wikipédia: http://en.wikipedia.org/wiki/Quote_notation .

il n'y a rien qui dit que nous ne pouvons pas ajouter un symbole à notre système de représentation, de sorte que nous pouvons représenter les rationales décimales exactement en utilisant la notation de citation binaire, et vice versa.

9
répondu ntownsend 2009-09-25 14:36:19

BCD - décimal binaire codé - les représentations sont exactes. Ils ne sont pas très économes en espace, mais c'est un compromis que vous devez faire pour la précision dans ce cas.

5
répondu Alan 2009-07-06 20:21:05

si vous faites un nombre assez grand avec la virgule flottante (comme il peut faire des exposants), alors vous finirez avec l'inexactitude devant la virgule décimale, aussi. Donc, je ne pense pas que votre question est entièrement valide parce que la prémisse est fausse; ce n'est pas le cas que le déplacement de 10 créera toujours plus de précision, parce qu'à un certain point le nombre de virgule flottante devra utiliser des exposants pour représenter la grandeur du nombre et perdra un peu de précision de cette façon aussi bien.

4
répondu Daniel Lew 2009-07-06 20:20:43

c'est la même raison que vous ne pouvez pas représenter 1/3 exactement en base 10, vous devez dire 0.33333(3). En binaire, c'est le même type de problème, mais se produit juste pour un ensemble différent de nombres.

4
répondu James 2009-07-06 20:30:52

(Note: je vais ajouter 'b' pour indiquer des nombres binaires ici. Tous les autres nombres sont donnés en décimal)

une façon de penser les choses est en termes de notation scientifique. Nous sommes habitués à voir des nombres exprimés en notation scientifique comme, 6.022141 * 10^23. Les nombres à virgule flottante sont stockés en interne en utilisant un format similaire - mantissa et exposant, mais en utilisant des pouvoirs de deux au lieu de dix.

Votre 61.0 pourrait être réécrit comme 1.90625 * 2^5, ou 1.11101 b * 2^101b avec la mantissa et les exposants. Pour multiplier cela par dix et (déplacer le point décimal), nous pouvons faire:

(1.90625 * 2^5) * (1.25 * 2^3) = (2.3828125 * 2^8) = (1.19140625 * 2^9)

ou dans avec le mantissa et exposants en binaire:

(1.11101 b * 2^101b) * (1.01 b * 2^11b) = (10.0110001 b * 2^1000b) = (1.00110001 b * 2^1001b)

notez ce que nous avons fait là pour multiplier les nombre. Nous avons multiplié les mantissas et ajouté les exposants. Puis, puisque le mantissa s'est terminé plus de deux, nous avons normalisé le résultat en cognant l'exposant. C'est comme quand nous ajustons l'exposant après avoir fait une opération sur les nombres en notation scientifique décimale. Dans chaque cas, les valeurs avec lesquelles nous avons travaillé ont eu une représentation finie en binaire, et donc les valeurs produites par les opérations de multiplication et d'addition de base ont également produit des valeurs avec une représentation finie.

voyez comment on divise 61 par 10. Nous commencerions par diviser les mantissas, 1.90625 et 1.25. En décimal, cela donne 1.525, un nombre court agréable. Mais qu'est-ce que cela si l'on convertit en binaire? Nous le ferons de la manière habituelle -- en soustrayant la plus grande puissance de deux autant que possible, tout comme en convertissant des décimales entières en décimales binaires, mais nous utiliserons des puissances négatives de deux:

1.525         - 1*2^0   --> 1
0.525         - 1*2^-1  --> 1
0.025         - 0*2^-2  --> 0
0.025         - 0*2^-3  --> 0
0.025         - 0*2^-4  --> 0
0.025         - 0*2^-5  --> 0
0.025         - 1*2^-6  --> 1
0.009375      - 1*2^-7  --> 1
0.0015625     - 0*2^-8  --> 0
0.0015625     - 0*2^-9  --> 0
0.0015625     - 1*2^-10 --> 1
0.0005859375  - 1*2^-11 --> 1
0.00009765625...

Uh oh. Maintenant, nous sommes en difficulté. Il s'avère que 1.90625 / 1,25 = 1,525, est une fraction répétée lorsqu'elle est exprimée en binaire: 1,11101 b / 1,01 b = 1,10000110011...b Nos machines ont seulement tellement de bits pour tenir que mantissa et donc ils vont juste arrondir la fraction et supposent des zéros au-delà d'un certain point. L'erreur que vous voyez lorsque vous divisez 61 par 10 est la différence entre:

1.10000110011001100110011001100110011001100110011...b * 2^10b

et, dire:

1.100001100110011001100110 b * 2^10b

c'est cet arrondi de la mantissa qui conduit à la perte de précision que nous associons aux valeurs à virgule flottante. Même lorsque le mantissa peut être exprimé exactement (par exemple, en ajoutant seulement deux nombres), nous pouvons toujours obtenir la perte numérique si le mantissa a besoin de trop de chiffres pour s'adapter après la normalisation de l'exposant.

Nous faisons ce genre de chose tout le temps quand nous autour des nombres décimaux à une taille gérable et de donner les premiers chiffres de il. Parce que nous exprimons le résultat en décimal, cela semble naturel. Mais si on arrondit une décimale et qu'on la convertit en une base différente, ça aura l'air aussi laid que les décimales qu'on a à cause de l'arrondi à la virgule flottante.

4
répondu Boojum 2009-07-06 21:57:14

C'est une bonne question.

toute votre question est basée sur "comment représenter un nombre?"

tous les nombres peuvent être représentés avec une représentation décimale ou avec une représentation binaire (complément de 2). tous !!

mais certains (la plupart d'entre eux) nécessitent un nombre infini d'éléments ("0" ou" 1 " pour la position binaire, ou "0", " 1 " à " 9 " pour la décimale représentation.)

comme 1/3 dans la représentation décimale (1/3 = 0,333333... <- avec un nombre infini de "3")

comme 0,1 en binaire (0,1 = 0,00011001100110011.... <- avec un nombre infini de "0011")

tout est dans ce concept. Puisque votre ordinateur ne peut considérer fini jeu de chiffres (décimal OU binaire), seulement quelques nombres peuvent être exactement représentés dans votre ordinateur...

et comme dit Jon, 3 est un nombre premier qui n'est pas un facteur de 10, donc 1/3 ne peut pas être représenté avec un fini nombre d'éléments en base 10.

même avec une précision arithmétique arbitraire, le système de position de numérotation de la base 2 n'est pas en mesure de décrire pleinement 6.1, bien qu'il puisse représenter 61.

pour 6.1, nous devons utiliser une autre représentation (comme la représentation décimale, ou IEEE 854 qui autorise la base 2 ou la base 10 pour la représentation des valeurs à virgule flottante)

4
répondu ThibThib 2009-07-06 22:18:15

je suis surpris que personne n'ait encore déclaré ceci: utilisez fractions continues . N'importe quel nombre rationnel peut être représenté finiment en binaire de cette façon.

quelques exemples:

1/3 (0,3333...)

0; 3

5/9 (0.5555...)

0; 1, 1, 4

10/43 (0.232558139534883720930...)

0; 4, 3, 3

9093/18478 (0.492098711981821387596060179673...)

0; 2, 31, 7, 8, 5

D'ici, il y a une variété de façons connues de stocker une séquence d'entiers en mémoire.

en plus de stocker votre nombre avec une précision parfaite, fractions continues ont également quelques autres avantages, tels que la meilleure approximation rationnelle. Si vous décidez de terminer la séquence de nombres dans une fraction continue tôt, les chiffres restants (quand recombiné à une fraction) vous donnera la meilleure fraction possible. C'est de cette façon on trouve des approximations de pi:

fraction continue de Pi:

3; 7, 15, 1, 292 ...

termine la séquence à 1, ce qui donne la fraction:

355/113

qui est une excellente approximation rationnelle.

3
répondu Nick 2011-01-03 14:49:08

dans l'équation

2^x = y ;  
x = log(y) / log(2)

donc, je me demandais si nous pouvions avoir un système de base logarithmique pour les binaires comme,

 2^1, 2^0, 2^(log(1/2) / log(2)), 2^(log(1/4) / log(2)), 2^(log(1/8) / log(2)),2^(log(1/16) / log(2)) ........

qui pourrait être capable de résoudre le problème, donc si vous vouliez écrire quelque chose comme 32.41 en binaire, ce serait

2^5 + 2^(log(0.4) / log(2)) + 2^(log(0.01) / log(2))

ou

2^5 + 2^(log(0.41) / log(2))
2
répondu rachit_verma 2014-02-22 15:59:39

le problème est que vous ne savez pas vraiment si le nombre est exactement 61.0 . Considérez ceci:


float a = 60;
float b = 0.1;
float c = a + b * 10;

Quelle est la valeur de c? Ce n'est pas exactement 61, parce que b ne l'est pas vraiment .1 parce que .1 n'a pas de représentation binaire exacte.

1
répondu Dima 2009-07-06 20:21:19

il y a un seuil parce que la signification du chiffre est passée d'entier à non-entier. À 61, vous avez 6*10^1 + 1*10^0; 10^1 et 10^0 sont deux entiers. 6.1 6*10^0 + 1*10^-1, mais 10^-1 est de 1/10, ce qui n'est certainement pas un entier. C'est comme ça qu'on finit à Inexactville.

1
répondu Mark Ransom 2009-07-06 20:48:45

un parallèle peut être fait de fractions et de nombres entiers. Certaines fractions, par exemple 1/7, ne peuvent pas être représentées sous forme décimale sans lots et lots de décimales. Parce que floating point est binaire basé les cas spéciaux changent mais le même genre de problèmes de précision se présentent.

1
répondu mP. 2009-07-06 21:03:07

Il y a un nombre infini de nombres rationnels, et un nombre fini de bits pour le représenter. Voir http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems .

0
répondu zpasternack 2009-07-06 20:33:07

le nombre 61.0 a effectivement une opération exacte à virgule flottante-mais ce n'est pas vrai pour tous entiers. Si vous avez écrit une boucle qui a ajouté un à la fois un nombre flottant de double précision et un entier 64 bits, éventuellement vous atteindriez un point où l'entier 64 bits représente parfaitement un nombre, mais le point flottant ne le fait pas-parce qu'il n'y a pas assez de bits significatifs.

il est juste beaucoup plus facile d'atteindre le point de approximation du côté droit du point décimal. Si vous commenciez à écrire tous les nombres en virgule flottante binaire, ça aurait plus de sens.

une autre façon de penser à ce sujet est que lorsque vous notez que 61.0 est parfaitement représentable en base 10, et en déplaçant le point décimal autour ne change pas cela, vous effectuez la multiplication par des puissances de dix (10^1, 10^-1). En virgule flottante, la multiplication par des puissances de deux, n'affecte pas la précision du nombre. Essayer prendre 61.0 et le diviser par trois à plusieurs reprises pour une illustration de la façon dont un nombre parfaitement précis peut perdre sa représentation précise.

0
répondu John Calsbeek 2009-07-06 20:36:25

vous connaissez les nombres entiers? chaque bit représente 2^n



2^4 = 16

2^3=8

2^2=4

2^1=2

2^0=1

c'est bien la même chose pour la virgule flottante (avec quelques distinctions) mais les bits représentent 2^ - n 2^-1=1/2=0.5

2^-2=1/(2*2)=0.25

2^-3=0.125

2^-4=0.0625

Floating point binaire representation:

signe fraction exposant (je pense invisible 1 est ajouté à la fraction )

B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0

0
répondu yan bellavance 2009-07-06 21:11:12

la réponse la mieux notée ci-dessus a cloué le clou.

d'abord vous mélangiez la base 2 et la base 10 dans votre question, puis quand vous mettez un nombre sur le côté droit qui n'est pas divisible dans la base vous obtenez des problèmes. Comme 1/3 en décimale parce que 3 ne va pas dans une puissance de 10 ou 1/5 en binaire qui ne va pas dans une puissance de 2.

un autre commentaire bien que ne jamais utiliser égal avec des nombres à virgule flottante, période. Même si elle est une représentation exacte il y a quelques nombres dans certains systèmes à virgule flottante qui peuvent être représentés avec précision de plus d'une façon (IEEE est mauvais à ce sujet, c'est une horrible spécification à virgule flottante pour commencer, alors attendez-vous à des maux de tête). Pas de différence ici 1/3 n'est pas égal au nombre sur votre calculatrice 0.3333333, peu importe combien de 3 Il y a à la droite du point décimal. Il est ou peut être assez proche mais n'est pas égal. donc vous attendre à quelque chose comme 2*1/3 de pas égal à 2/3 selon l'arrondissement. Jamais l'utilisation d'égal à égal avec virgule flottante.

0
répondu old_timer 2009-07-10 21:18:54

comme nous en avons discuté, en arithmétique à virgule flottante, la décimale 0.1 ne peut pas être parfaitement représentée en binaire.

les représentations en virgule flottante et en nombre entier fournissent des grilles ou des treillis pour les nombres représentés. Comme l'arithmétique est fait, les résultats tombent hors de la grille et doivent être remis sur la grille en arrondissant. Exemple de 1/10 sur une grille binaire.

si nous utilisons la représentation décimale codée binaire comme un gentleman suggéré, pourrions-nous garder les nombres sur la grille?

0
répondu Joe 2011-02-15 08:53:53