2010-11-19 12 views
52

この質問は、私は常にデフォルトでdouble-precisionするMATLAB変数を理解MATLABでは、デフォルトで変数は本当に倍精度ですか?

...さらにthis questionを調査した後、私は気づいたという奇妙な何かの外に生まれました。だから、私は、小数点以下20桁で変数を宣言するような何かをした場合:

>> num = 2.71828182845904553488; 
>> class(num) %# Display the variable type 
ans = 
double 
私は floating-point relative accuracyは10 -16程度であるので、最後の4桁が、無視されることを期待する

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

私は(FPRINTFまたはSPRINTFのいずれかを使用して)小数点以下16の以上の数字で番号を表示しようとすると、私は私が見ることを期待ものを手に入れる:

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

、数字17〜20は全て0

しかし、私はSymbolic Toolboxvariable precision arithmetic functionnumを渡す際に物事が精度の21桁使って数を表すために、それを言って、おかしく:

>> vpa(num,21) 
ans = 
2.71828182845904553488 

WHAT ?!最後の4桁が再表示されました!入力した元の数値が倍精度変数numとして保存されていたときにそれらが失われてはいけませんか? vpaに渡されたときにnumが倍精度変数であるため、vpaはどのようにしてそれらが分かったのですか?

MATLAB内部では、double精度の変数よりも小数点以下の桁数で初期化して以来、doubleより精度が高いnumが内部的に表現されています。これは実際に何が起こっているのですか、それとも何か他のことが起こっていますか?



BONUS:あなたはすでに上から片頭痛を持っていない場合そして、ここでは、混乱の追加ソースです...

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

答えて

51

彼らはダブルスのです。 Vpa()は単に浮動小数点の相対精度を超えて、printf()とdisp()が切り捨てられたりゼロになったりすることなく、無効な数字を表示することを選択しています。

numを初期化するために選択したリテラルが、バイナリdouble値の正確な小数点以下の拡張子になるため、元の4桁の数字が戻されます。これは、拡張子の出力からコピーされ貼り付けられたためです他の質問からの実際の二重価値のあなたの "BONUS"補遺に示すように、近くの他の値に対しては機能しません。

より正確には、Matlabのすべての数値リテラルはdouble型の値を生成します。それらは、それらが表す小数値に最も近いバイナリのdouble値に変換されます。実際には、double型の精度の限界を超えたリテラルの数字は、静かにドロップされます。vpaの出力をコピーして貼り付けて新しい変数を作成すると、もう1つの質問のポスターが "e = ..."ステートメントで行ったように、結果を直接扱うのではなく、リテラルから値を初期化しています。前の式。

ここでの違いは、出力フォーマットのみです。私は、vpa()がその倍精度バイナリをdoubleとし、それを正確な値として扱っていることを考えています。与えられた2進仮数 - 指数値に対して、任意に多くの小数点以下の桁に相当する小数点を計算することができます。固定長データ型と同様に、バイナリ値の精度(「幅」)が限られている場合は、そのような10進数の数だけが重要です。 Sprintf()とMatlabのデフォルト表示では、出力を切り捨てるか、無効な数字を0として表示します。Vpa()は精度の限界を無視し、要求した小数点以下の桁数を計算し続けます。

これらの追加の数字は、彼らが近く小数点値を生成するために他の値に置き換えた場合、それらはすべて同じバイナリdouble値に「丸い」になるだろうという意味では、偽です。

ここにその方法を示します。これらのxの値は、倍精度で格納されたときはすべて同じで、すべてvpa()によって同じになります。

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

これを示す別の方法があります。お互いに非常に近い2つのダブルスがあります。

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

Vpaは(X0)とVPA(X1)が16桁を超えて多くの異なる出力を生成する必要があります。ただし、vpa(x)がvpa(x0)とvpa(x1)の間の10進表現を生成するようなdouble値xを作成するべきではありません。

(UPDATE:。。アムロは、あなたが16進形式の根底にあるバイナリ値の正確な表現を表示するためにfprintf('%bx\n', x)を使用できることを指摘するあなたはリテラルが同じ二重にマップを確認するためにこれを使用することができます)

私は疑いますvpa()は入力を厳密な値として扱い、Symbols Toolboxの倍精度よりも精度の高い他のMatlab型を多態的にサポートするため、このように動作します。これらの値は、数値リテラル以外の方法で初期化する必要があります。これは、sym()が入力として文字列を取り、 "vpa(exp(1))"が "vpa(sym( 'exp(1)') )」。

意味がありますか?長い風には申し訳ありません。

(私はSymbolic Toolboxを持っていないので、vpa()は自分でテストできません)

+1

+1興味深い質問への有益な答え! – Jonas

+1

Aha!だから私はちょうど私のテスト番号としてバイナリ値の正確な小数の展開を使用していた。今はすべて意味があります!しかし、私がそれを見逃してしまったかどうかは確かではありません...娘が歯が抜けていて、徹夜していたので、睡眠不足が原因でした。 ;) – gnovice

+1

@Andrew:あなたはMathWorksで働いていますか? – Mikhail

関連する問題