Dans MATLAB, sont des variables VRAIMENT en 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 l' 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 termes, 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 le 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'elle est passée à vpa
, comment avez - vpa
savoir 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!!!
Vous devez vous connecter pour publier un commentaire.
Ils sont doubles.
vpa()
est tout simplement choisir d'afficher des chiffres non significatifs au-delà de la virgule flottante précision relative, oùprintf()
etdisp()
tronquer ou 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
vpa
pour créer une nouvelle variable, comme les questions des autres affiches ont fait avec lee = ...
déclaration, 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
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.printf()
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.vpa()
est ignorant 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
vpa()
.Voici une autre façon de démontrer qu'on. Voici deux doubles qui sont très proches les uns des autres.
vpa(x0)
etvpa(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 valeurx
tels quevpa(x)
produit une représentation décimale qui tombe entrevpa(x0)
etvpa(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
vpa()
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 pourquoisym()
prend une chaîne de caractères en entrée etvpa(exp(1))
diffère devpa(sym('exp(1)'))
.Sens? Désolé pour le long-windedness.
(Remarque je n'ai pas la Symbolique boîte à outils, donc je ne peux pas tester
vpa()
moi-même.)fprintf('%bx\n', exp(1), 2.7182818284590455, 2.71828182845904559999999999)
et ils seront tous de retour de la même 64 bits représentation4005bf0a8b14576a
fprintf('%bx\n', exp(1), exp(1)+eps(exp(1)))
(au moins pour cette valeur). Incorporer ce en un de côté dans ma réponse.première :
il semble que sprintf et fprintf ont un comportement différent sur les différentes versions de MATLAB
par exemple dans MATLAB 2018 une
deuxième :
consulter ce lien pour plus d'infos
donc dans votre cas où n=1 (2^1 <= num <= 2^2), l'espacement est de 2^-51 ,
je pense qu'il est sûr de supposer que sprintf et sprintf algorithmes pour montrer les chiffres sont difficiles et MATLAB Double type est basé sur la norme IEEE,
sur l'APV:
Numériquement approximative 1/3 à l'aide de quatre chiffres significatifs.
Approximative le résultat d'une aide de 20 chiffres. Le résultat montre que la boîte à outils à usage interne de plus de quatre chiffres pour le calcul de la. Les derniers chiffres du résultat sont incorrectes à cause de l'erreur d'arrondi.
le problème que vous pouvez rencontrer est en raison de l'espacement , gaurd chiffres de l'algorithme et d'arrondir problème ,
par exemple à l'aide de matlab 2018 une :
mais:
parce que le nombre est compris entre 2^3 et 2^4 donc l'espacement est de 2^-49 (= 1.77 e-15)
si le nombre est valable jusqu'au 15 décimale
et
parce que le nombre est compris entre 2^6 et 2^7 si l'espacement est de 2^-46 (= 1.42 e-14)
si le nombre est valable jusqu'au 14 décimale