web-dev-qa-db-fra.com

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

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!!!
70
gnovice

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

3
Hadi