Diese Frage entstand aus etwas Seltsamem, das mir auffiel, nachdem ich diese Frage weiter untersucht hatte ...
Ich habe MATLAB-Variablen immer standardmäßig als doppelt genau verstanden . Wenn ich also so etwas wie eine Variable mit 20 Nachkommastellen deklarieren würde:
>> num = 2.71828182845904553488;
>> class(num) % Display the variable type
ans =
double
Ich würde erwarten, dass die letzten 4 Ziffern ignoriert werden, da die relative Genauigkeit des Gleitkommas in der Größenordnung von 10-16 liegt :
>> eps(num)
ans =
4.440892098500626e-016
Wenn ich versuche, die Zahl mit mehr als 16 Nachkommastellen anzuzeigen (entweder mit fprintf
oder sprintf
), erhalte ich das, was ich erwartet habe:
>> fprintf('%0.20f\n', num)
2.71828182845904550000
>> sprintf('%0.20f', num)
ans =
2.71828182845904550000
Mit anderen Worten, die Ziffern 17 bis 20 sind alle 0.
Aber es wird merkwürdig, wenn ich num
zur arithmetischen Funktion mit variabler Genauigkeit in der Symbolic Toolbox übergebe und sie auffordere , die Zahl mit 21 Stellen Genauigkeit darzustellen:
>> vpa(num, 21)
ans =
2.71828182845904553488
WAS?! Diese letzten 4 Ziffern sind wieder aufgetaucht! Sollten sie nicht verloren gegangen sein, als die von mir eingegebene ursprüngliche Nummer als Variable mit doppelter Genauigkeit gespeichert wurde num
? Da num
eine doppelte Genauigkeit Variable ist , wenn es um übergeben wird vpa
, wie hat vpa
weiß , was sie waren?
num
Ich gehe davon aus, dass MATLAB intern genauer als ein Doppel darstellt, da ich es mit einer Zahl initialisiert habe, deren Ziffern über dem Dezimalpunkt liegen, als eine Variable mit doppelter Genauigkeit verarbeiten könnte. Passiert das wirklich oder ist etwas anderes los?
BONUS: Und hier ist eine zusätzliche Quelle der Verwirrung, wenn Sie noch keine Migräne von oben haben ...
>> 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!!!
quelle
fprintf('%bx\n', exp(1), 2.7182818284590455, 2.71828182845904559999999999)
und sie werden alle die gleiche 64-Bit-Darstellung zurückgeben4005bf0a8b14576a
fprintf('%bx\n', exp(1), exp(1)+eps(exp(1)))
(zumindest für diesen Wert). Dies in meiner Antwort beiseite zu nehmen.zuerst :
Es scheint, dass sprintf und fprintf in verschiedenen Versionen von MATLAB ein unterschiedliches Verhalten aufweisen, beispielsweise in MATLAB 2018 a
num=2.7182818284590666666666; sprintf('%0.70f', num) ans = '2.7182818284590668511668809514958411455154418945312500000000000000000000'
zweite :
Weitere Informationen finden Sie unter diesem Link
In Ihrem Fall, in dem n = 1 (2 ^ 1 <= num <= 2 ^ 2) ist, beträgt der Abstand 2 ^ -51.
Ich denke, es ist sicher anzunehmen, dass Sprintf- und Sprintf-Algorithmen zum Anzeigen von Zahlen schwierig sind und der MATLAB Double-Typ auf dem IEEE-Standard basiert.
über VPA:
Numerisch ungefähr 1/3 mit vier signifikanten Ziffern.
a = vpa(1/3, 4) a = 0.3333
Schätzen Sie das Ergebnis mit 20 Ziffern ein. Das Ergebnis zeigt, dass die Toolbox bei der Berechnung von a intern mehr als vier Ziffern verwendet hat. Die letzten Ziffern im Ergebnis sind aufgrund des Rundungsfehlers falsch.
vpa(a, 20) ans = 0.33333333333303016843
Das Problem, auf das Sie möglicherweise stoßen, ist auf den Abstand, den Gaurd-Ziffern-Algorithmus und das Rundungsproblem zurückzuführen.
zum Beispiel mit matlab 2018 a:
sprintf('%0.28f', 8.0) ans = '8.0000000000000000000000000000'
aber:
sprintf('%0.28f', 8.1) ans = '8.0999999999999996447286321199'
Da die Zahl zwischen 2 ^ 3 und 2 ^ 4 liegt, beträgt der Abstand 2 ^ -49 (= 1,77 e-15), sodass die Zahl bis zur 15. Dezimalstelle und gültig ist
sprintf('%0.28f', 64.1) ans = '64.0999999999999943156581139192'
Da die Zahl zwischen 2 ^ 6 und 2 ^ 7 liegt, beträgt der Abstand 2 ^ -46 (= 1,42 e-14), sodass die Zahl bis zur 14. Dezimalstelle gültig ist
quelle