Cette question est née de quelque chose d'étrange que j'ai remarqué après enquête cette question plus loin ...
J'ai toujours compris que les variables MATLAB étaient double précision par défaut. Donc, si je devais faire quelque chose comme déclarer une variable avec 20 chiffres après le point décimal:
>> num = 2.71828182845904553488;
>> class(num) % Display the variable type
ans =
double
Je m'attendrais à ce que les 4 derniers chiffres soient ignorés, car la précision relative à virgule flottante 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 la virgule décimale (en utilisant fprintf
ou sprintf
), j'obtiens ce que j'attends de voir:
>> fprintf('%0.20f\n', num)
2.71828182845904550000
>> sprintf('%0.20f', num)
ans =
2.71828182845904550000
En d'autres termes, les chiffres 17 à 20 sont tous 0.
Mais les choses deviennent bizarres quand je passe num
à fonction arithmétique à précision variable dans Symbolic Toolbox , en lui disant de représenter le nombre en utilisant 21 chiffres de précision:
>> vpa(num, 21)
ans =
2.71828182845904553488
QUOI?! Ces 4 derniers chiffres sont réapparus! Ne devraient-ils pas être perdus lorsque le numéro d'origine que j'ai entré a été enregistré en tant que variable à double précision num
? Puisque num
est une variable à double précision lorsqu'elle est passée à vpa
, comment vpa
a-t-il su de quoi il s'agissait?
Ma meilleure supposition quant à ce qui se passe est que MATLAB représente en interne num
avec plus de précision qu'un double puisque je l'ai initialisé à un nombre avec plus de chiffres après le point décimal qu'une variable à double précision pourrait gérer. Est-ce vraiment ce qui se passe ou quelque chose d'autre se passe-t-il?
BONUS: Et voici une source de confusion supplémentaire si vous n'avez pas déjà une migraine de ce qui précède ...
>> 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!!!
premier :
il semble que sprintf et fprintf ont un comportement différent sur différentes versions de MATLAB par exemple dans MATLAB 2018 a
num=2.7182818284590666666666;
sprintf('%0.70f', num)
ans =
'2.7182818284590668511668809514958411455154418945312500000000000000000000'
seconde :
Nombres à virgule flottante
MATLAB® représente des nombres à virgule flottante au format double précision ou simple précision. La valeur par défaut est double précision, mais vous pouvez rendre n'importe quel nombre simple précision avec une fonction de conversion simple.
Virgule flottante double précision
MATLAB construit le type de données double précision (ou double) selon la norme IEEE® 754 pour la double précision. Toute valeur stockée sous forme de double nécessite 64 bits, formatée comme indiqué dans le tableau ci-dessous:
Bits: 63
Utilisation: signe (0 = positif, 1 = négatif)Bits: 62 à 52 Utilisation: exposant, biaisé par 1023
Bits: 51 à 0 Utilisation: fraction f du nombre 1.f
se référer à ce lien pour plus d'informations
Entre 252 = 4.503.599.627.370.496 et 253 = 9.007.199.254.740.992, les nombres représentables sont exactement les nombres entiers. Pour la plage suivante, de 253 à 254, tout est multiplié par 2, donc les nombres représentables sont les nombres pairs, etc. Inversement, pour la plage précédente de 2 ^ 51 à 2 ^ 52, l'espacement est de 0,5, etc.
L'espacement en tant que fraction des nombres compris entre 2 ^ n et 2 ^ n + 1 est de 2 ^ n − 52. L'erreur d'arrondi relative maximale lors de l'arrondi d'un nombre au nombre représentable le plus proche (la machine epsilon) est donc de 2 ^ −53.
donc dans votre cas où n = 1 (2 ^ 1 <= num <= 2 ^ 2) l'espacement est 2 ^ -51,
je pense qu'il est sûr de supposer que les algorithmes sprintf et sprintf pour afficher les nombres sont délicats et le type MATLAB Double est basé sur la norme IEEE,
à propos de l'APV:
vpa utilise des chiffres de garde pour maintenir la précision
La valeur de la fonction digits spécifie le nombre minimum de chiffres significatifs utilisés. En interne, vpa peut utiliser plus de chiffres que de chiffres spécifiés. Ces chiffres supplémentaires sont appelés chiffres de garde car ils protègent contre les erreurs d'arrondi dans les calculs ultérieurs.
Numériquement approximativement 1/3 en utilisant quatre chiffres significatifs.
a = vpa(1/3, 4)
a =
0.3333
Approximer le résultat en utilisant 20 chiffres. Le résultat montre que la boîte à outils a utilisé en interne plus de quatre chiffres lors du calcul de a. Les derniers chiffres du résultat sont incorrects en raison de l'erreur d'arrondi.
vpa(a, 20)
ans =
0.33333333333303016843
le problème que vous pouvez rencontrer est dû à l'espacement, à l'algorithme des chiffres de gaurd et au problème d'arrondi,
par exemple en utilisant matlab 2018 a:
sprintf('%0.28f', 8.0)
ans =
'8.0000000000000000000000000000'
mais:
sprintf('%0.28f', 8.1)
ans =
'8.0999999999999996447286321199'
parce que le nombre est compris entre 2 ^ 3 et 2 ^ 4 donc l'espacement est de 2 ^ -49 (= 1,77 e-15) donc le nombre est valable jusqu'à la 15ème décimale et
sprintf('%0.28f', 64.1)
ans =
'64.0999999999999943156581139192'
parce que le nombre est compris entre 2 ^ 6 et 2 ^ 7 donc l'espacement est de 2 ^ -46 (= 1,42 e-14) donc le nombre est valable jusqu'à la 14ème décimale