C#
a le decimal
type utilisé pour les nombres nécessitant une représentation exacte en base 10. Par exemple, 0.1
ne peut pas être représenté en base 2 (par exemple, float
et double
) et sera toujours une approximation lorsqu'il est stocké dans des variables de ces types.
Je me demandais si le fait inverse était également possible. Existe-t-il des nombres qui ne sont pas représentables en base 10 mais qui peuvent être représentés en base 2 (dans ce cas, je souhaiterais utiliser un à la float
place d'un decimal
pour les traiter)?
0.11_b2
, écrivez-le sous forme de0.5 + 0.5 * 0.5
. Existe-t-il une étape qui pourrait échouer ou donner lieu à une répétition du nombre décimal? Personnellement, je trouve que cet exercice fait un excellent travail pour comprendre une intuition sur les nombres de base 2. Je suppose que l’on pourrait aller plus loin et transformer cet exercice en une preuve par construction.0.0999999....998..
exactement, mais pas le nombre entier0.1
. Des approximations telles que l'arrondi au centième le plus proche0.100
sont un problème d'implémentation qui implique de ne pas vous montrer tous les chiffres et de les arrondir.Réponses:
Voici la clé de votre dilemme:
10
le produit de2
et5
. Vous pouvez représenter n’importe quel nombre exactement en décimales base 10, c’est k * 1/2 n * 1/5 m oùk
,n
etm
sont des entiers.Autrement dit - si le nombre
n
dans 1 / n contient un facteur qui ne fait pas partie des facteurs de la base, le nombre ne pourra pas être représenté exactement par un nombre fixe de chiffres dans le développement binaire / décimal / quel que soit nombre - il aura une partie répétitive. Par exemple, 1/15 = 0,0666666666 .... car 3 (15 = 3 * 5) n'est pas un facteur de 10.Ainsi, tout ce qui peut être représenté en base 2 exactement (k * 1/2 n ) peut être représenté en base 10 exactement.
Au-delà de cela, il y a la question du nombre de chiffres / bits que vous utilisez pour représenter le nombre. Il y a des nombres qui peuvent être représentés exactement dans une base, mais cela prend plus qu'un certain nombre de chiffres / bits à faire.
En binaire, le nombre 1/10, qui est commodément 0,1 en décimal, ne peut pas être représenté par un nombre pouvant être représenté par un nombre fixe de bits en binaire. Au lieu de cela, le nombre est 0.00011001100110011 ... 2 (avec la partie 0011 répétée pour toujours).
Regardons le numéro 1 2 /1010 2 un peu plus près.
C'est exactement le même type de chose que vous obtenez lorsque vous essayez de faire la division longue pour 1/3.
1/10, lorsque factorisé vaut 1 / (2 1 * 5 1 ). Pour la base 10 (ou tout multiple de 10), ce numéro se termine et est appelé un nombre normal . Une expansion décimale qui se répète est appelée décimale répétitive et les nombres qui durent indéfiniment sans se répéter sont des nombres irrationnels.
Le calcul derrière ce Delves dans le petit théorème de Fermat ... et une fois que vous commencez à dire Fermat ou théorème, il devient une question Math.SE .
La réponse est non'.
Donc, à ce stade, nous devrions tous être clairement conscients que tout développement binaire de longueur fixe d’un nombre rationnel peut être représenté par un développement décimal de longueur fixe.
Permet de regarder de plus près à la décimale en C # qui nous amène à virgule flottante décimal dans .NET et étant donné l'auteur, j'accepte que thats comment ça marche.
Je ferai remarquer tout de suite que, du fait de cette mise en œuvre, il y a des nombres dans le
double
type qui ne peuvent pas être représentésdecimal
- ceux qui sont hors de portée.Double.Epsilon
est4.94065645841247e-324
ce qui ne peut pas être représenté dans undecimal
, mais peut dans undouble
.Toutefois, dans la plage que peut représenter le nombre décimal, il a plus de bits de précision que les autres types natifs et peut les représenter sans erreur.
Il y a d'autres types qui circulent. Il existe un BigInteger dans C # qui peut représenter un entier arbitrairement grand. Il n'y a pas d' équivalent à Java BigDecimal (qui peut représenter des nombres avec décimales jusqu'à 2 32 chiffres longs - ce qui est une gamme importante) exactement . Cependant, si vous fouillez un peu, vous pouvez trouver des implémentations roulées à la main.
Certaines langues ont aussi un type de données rationnel qui vous permet de représenter exactement les rationnels (donc 1/3 est égal à 1/3).
Spécifiquement pour C # et le choix de float ou rationnel, je laisserai la parole à Jon Skeet de la pinte flottante Decimal dans .NET :
la source
n = 15
etb = 10
ne sont pas relativement premiers ("ne partage aucun facteur positif commun (diviseurs) sauf 1") car ils partagent le facteur 5. La clé est que tous les facteurs de 15 (5 et 3) ne sont pas aussi des facteurs de 10. (Existe-t-il un mot pour indiquer des nombres qui partagent ou non tous les facteurs communs?) Je pense que cela est parfaitement enveloppé dans votrek, n, m
équation, mais pour bien comprendre, j’aurais besoin de voir un complot en 3D. Quoi qu'il en soit, vous avez bien mérité une +1.Une fois que vous sortez de la plage de valeurs acceptables, la réponse est oui. Cela dit, presque tout dans la fourchette aura une représentation. Référence décimale C # Bien que cela ne soit pas indiqué dans la spécification, les nombres irrationnels ne peuvent pas être représentés exactement (par exemple, e 1 , pi, la racine carrée de 2, etc.).
1 Merci à MichaelT de m'avoir rappelé un autre nombre irrationnel.
la source
e
(2,71 ...). Le log naturel - ln (x) est log base e. Ainsi, les bases irrationnelles existent et sont utiles. Je ne suis pas sûr de l'utilité particulière de la base pi, mais cela ne veut pas dire qu'elle n'est pas utilisée quelque part.Un type à virgule flottante de base deux serait capable de représenter avec précision de nombreuses valeurs qu'un type de base dix de même taille ne pourrait pas. Toute valeur qui serait exactement représentable par un type de base 2 d'une certaine taille serait exactement représentable dans un type de base dix d'une taille suffisante. La taille requise pour un type purement en base dix pour représenter toutes les valeurs d'un nombre à virgule flottante binaire dépend de la plage de l'exposant du type binaire; des centaines de bits pour un
float
, ou des milliers pour undouble
.Cela étant dit, le
Decimal
type est suffisamment grand pour pouvoir être utilisé comme type "universel", capable de contenir la valeur de toute autre primitive numérique et de fournir quelques autres fonctionnalités supplémentaires (si rien d'autre, utilisez un bit pour indiquer si la valeur stockée est le résultat de la conversion dedouble
, et si ce bit est défini, utilisez 64 bits pour conserver la valeur en question). Microsoft a toutefois choisi de ne pas le faire. En conséquence, la conversion d'undouble
àDecimal
échouera complètement pour les grandes valeurs, entraînera les petites valeurs doivent être arrondies à 1E-28 le plus proche. En outre, même dans la plage dynamique dedecimal
, la méthode de conversion ne sera pas "aller-retour". Par exemple, évaluer 1,0 / 3,0 en tant que double donnera 0,3333333333333333148, mais le convertir en nombre décimal donnera 0,333333333333333m et le convertir en double produirait 0,3333333333333329818.la source