73 votes

Dans MATLAB, les variables sont-elles VRAIMENT double précision par défaut?

Cette question s'est posée de quelque chose d'étrange que j'ai remarqué après avoir enquêté sur cette question plus loin...

J'ai toujours compris MATLAB variables à double précision par défaut. Donc, si je devais faire quelque chose comme déclarer une variable avec 20 chiffres après la virgule:

>> num = 2.71828182845904553488;
>> class(num)  %# Display the variable type
ans =
double

Je m'attends à ce que les 4 derniers chiffres pour être ignoré, car la virgule flottante à précision relative est de l'ordre de 10-16:

>> eps(num)
ans =
    4.440892098500626e-016

Si j'essaie d'afficher le nombre avec plus de 16 chiffres après le point décimal (à l'aide de FPRINTF ou SPRINTF), j'obtiens ce que je m'attends à voir:

>> fprintf('%0.20f\n',num)
2.71828182845904550000
>> sprintf('%0.20f',num)
ans =
2.71828182845904550000

En d'autres mots, les chiffres de 17 à 20 sont tous 0.

Mais les choses deviennent étranges quand je passe la num à la précision variable fonction arithmétique dans la Symbolique boîte à outils, en disant qu'il représentent le nombre à l'aide de 21 chiffres de précision:

>> vpa(num,21)
ans =
2.71828182845904553488

QUOI?! Ces 4 derniers chiffres ont réapparu! N'ont-elles pas été perdue lorsque le nombre d'origine, je suis entré a été stocké dans une variable double précision num? Depuis num est une variable double précision lorsqu'il est passé à l' vpa, comment avez - vpa savent ce qu'ils étaient?

Ma meilleure supposition de ce qui se passe est que MATLAB représente en interne num avec plus de précision qu'un double depuis que j'ai initialisé à un nombre avec plus de chiffres après la virgule qu'une variable double précision pourrait manipuler. Est-ce vraiment ce qui se passe, ou autre chose?



BONUS: Et voici une autre source de confusion si vous ne l'avez pas déjà une migraine à partir de ci-dessus...

>> num = 2.71828182845904553488;  %# Declare with 20 digits past the decimal
>> num = 2.718281828459045531;    %# Re-declare with 18 digits past the decimal
>> vpa(num,21)
ans =
2.71828182845904553488  %# It's the original 20-digit number!!!

66voto

Andrew Janke Points 11942

Ils sont doubles. Apv() est tout simplement choisir d'afficher des chiffres non significatifs au-delà de la virgule flottante précision relative, où printf() et (disp) de tronquer ou de zéro dehors.

Vous êtes seulement obtenir l'original de votre quatre chiffres de retour parce que le littéral que vous avez choisi d'initialiser num avec seulement se trouve être l'exact décimal à l'expansion d'un binaire double de la valeur, car il a été copier-collé à partir de la sortie de l'extension d'une réelle valeur double de l'autre question. Il ne fonctionnera pas pour la proximité d'autres valeurs, comme vous le montrez dans votre "BONUS" additif.

Plus précisément, tous les littéraux numériques dans Matlab produire des valeurs de type double. Ils se converti à l'binaire double de la valeur qui est la plus proche à la valeur décimale de la valeur qu'ils représentent. En effet, les chiffres dans un littéral au-delà de la limite de précision du type double sont ignorés en mode silencieux. Lorsque vous copiez et collez la sortie de l'apv pour créer une nouvelle variable, comme les questions des autres affiches ont fait avec le "e = ..." énoncé, vous êtes à l'initialisation d'une valeur à partir d'un littéral, au lieu de traiter directement avec le résultat d'une expression précédente.

Les différences ici sont juste en sortie de mise en forme. Je pense que ce qui se passe est que le vpa() est de prendre de la double précision binaire double et la traiter comme une valeur exacte. Pour une donnée binaire mantisse-valeur d'exposant, vous pouvez calculer l'équivalent décimal de façon arbitraire, nombre de décimales. Si vous avez une précision limitée ("largeur") dans la valeur binaire, comme vous le faites avec n'importe quel de taille fixe, type de données, que beaucoup de ces chiffres décimaux sont importantes. Sprintf() et Matlab par défaut de l'affichage de gérer cela par la troncation de la sortie ou de l'affichage des chiffres non significatifs à 0. Apv (), c'est ignorer les limites de la précision et de continuer à calculer autant de décimales que vous demandez.

Ces chiffres sont faux, dans le sens que si elles ont été remplacées par d'autres valeurs pour produire de la proximité d'une valeur décimale, ils seraient tous get "arrondi" à la même binaire valeur double.

Voici une manière de le montrer. Ces valeurs de x sont tous les mêmes lorsqu'ils sont stockés dans des chambres doubles, et seront tous représentés de la même façon par l'apv().

x = [
    2.7182818284590455348848081484902650117874145507812500
    2.7182818284590455348848081484902650117874145507819999
    2.7182818284590455348848
    2.71828182845904553488485555555555555555555555555555
    exp(1)
    ]
unique(x)

Voici une autre façon de démontrer qu'on. Voici deux doubles qui sont très proches les uns des autres.

x0 = exp(1)
x1 = x0 + eps(x0)

Apv(x0) et apv(x1) devrait produire des résultats qui diffèrent beaucoup passé le 16e chiffres de. Cependant, vous ne devriez pas être en mesure de créer un double de la valeur de x telle que l'apv(x) produit une représentation décimale qui se situe entre la vpa(x0) et apv(x1).

(Mise à JOUR: Amro points que vous pouvez utiliser fprintf('%bx\n', x) pour afficher une représentation exacte du sous-jacent valeur binaire au format hex. Vous pouvez l'utiliser pour confirmer les littéraux de la carte à la même double.)

Je soupçonne apv() se comporte de cette façon, parce qu'il traite ses entrées comme des valeurs exactes, et polymorphically prend en charge d'autres Matlab types de la Symbolique boîte à outils qui ont plus de précision que doublé. Ces valeurs doivent être initialisés par des moyens autres que les littéraux numériques, c'est pourquoi sym() prend une chaîne de caractères en entrée et "apv(exp(1))" diffère de la "apv(sym (exp(1)'))".

Un sens? Désolé pour le long-windedness.

(Remarque je n'ai pas la Symbolique boîte à outils, donc je ne peux pas tester l'apv() moi-même.)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X