|
3.1.5 任意精度の数
計算が任意精度を持つ数に基づいて行われるとき,精度管理が全計算過程において取られる.そうすることで,入力値の精度に基づく最高精度で答が通常求まる.
Mathematica内部では,任意精度の数には有効な桁長は任意で限られた数しかなく,他の桁は未知である,とされる.一般に,任意精度の数xは確定している有効数字( Precision[x]の返す桁数)とそれに続く全く不確定な無限桁長の数字からなるものとして扱われる.
これは を10桁精度で計算する.
In[1]:= N[Pi, 10]
Out[1]= 
ある点を過ぎるとすべての桁が曖昧になる.
In[2]:= RealDigits[%, 10, 13]
Out[2]= 
式が入力され計算が始まると,計算結果のどの数字が入力値の持つ不確定な数字に影響されるか検討がなされる.そして影響を受けた数字が含まれないように精度が設定される.その結果,不確定な数字がどんな値であろうと,Mathematicaが出力する数字はすべて正しいものであることが保証される.
を30桁精度で計算する
In[3]:= N[Gamma[1/7], 30]
Out[3]= 
結果は厳密に30桁の精度である.
In[4]:= Precision[%]
Out[4]= 
数桁精度の値を入力すると,答の精度が落ちていることが分かる.
In[5]:= N[Gamma[0.142], 30]
Out[5]= 
引数が近似値でなく厳密な値142/1000であるならば,これをはっきりしなければいけない.
In[6]:= N[Gamma[142/1000], 30]
Out[6]= 
多くの計算問題で「丸め誤差」や「桁落ち誤差」が原因となり,計算ステップが重なるにつれ答の精度が次第に落ちてしまうことがある.このうち「桁落ち誤差」はほとんど同じ値を持った2つの数の差を取るときによく起る.接近した2数の差はその有効数字のうち末尾の方だけによって定まるが,一般的に,差を取る前の数に比べ答の有効数字の桁は非常に少なくなってしまう.
両入力値とも有効数字は20ある.しかし,答の有効数字は3に落ちてしまう.
In[7]:= 1.11111111111111111111 - 1.11111111111111111000
Out[7]= 
差を取る片方の数だけ桁精度を上げても,答の精度は上がらない.
In[8]:= 1.11111111111111111111345 - 1.11111111111111111000
Out[8]= 
関数の出力精度は引数の持つ精度(入力精度)に複雑な形で依存する.変化の激しい挙動を持つ関数は一般に出力精度が劣る.なぜかというと,同じ誤差を持つ引数を入力したら,変化の小さい関数に比べ,関数値により大きな出力変動幅が出てしまうからである.これに対して,定数関数に近い関数は入力精度より高い精度で関数値を返すときがある.
Sinのような関数は変化が早いので,出力は入力精度より劣ったものになってしまう.
In[9]:= Sin[111111111.0000000000000000]
Out[9]= 
の値を20桁精度で計算する.
In[10]:= N[Exp[-40], 20]
Out[10]= 
厳密な整数値1を加えると答がより高い精度を持つようになる.
In[11]:= 1 + %
Out[11]= 
一般に,同じ計算をいくつかの違う方法で行うと,精度が違った答が得られてしまうことを認識しておく必要がある.桁精度は1度失ったら取り戻せない.これは情報を失うことである.
40桁精度で1に近い値を持つ数を定義する.
In[12]:= x = N[1 - 10^-30, 40]
Out[12]= 
整数値 1を加算しても桁精度は落ちない.
In[13]:= 1 + x
Out[13]= 
確認してみると,40桁のままである.
In[14]:= Precision[%]
Out[14]= 
この例の式は,実は, 1 + xの値と同じ計算をするが,この式を使うと精度が落ちてしまう.
In[15]:= (x^2 - 1) / (x - 1)
Out[15]= 
やはりかなり精度が落ちてしまっている.
In[16]:= Precision[%]
Out[16]= 
上の例にもあったように,同じ計算をしても演算法を変えると違った近似値が答として求まってしまうときがある.このことから,2つの近接値の比較をするときは十分な注意をはらう必要があるといえる.Mathematicaが2つの数が等しいかどうかを判定するときは実効的な差を取る.そして,差が入力精度的に許容される幅の中にあるかどうか判定する.許容幅に収まる場合は「ゼロに一致」と解釈する.
2つの数は指定した桁精度内で等しい.
In[17]:= 3 == 3.000000000000000000
Out[17]= 
数学関数の計算に使う Mathematicaの内部アルゴリズムは,答の精度をなるべく高く保つように作られている.Mathematicaの組込み関数を使っている限り,通常,入力精度に対応する最高の精度で答が得られる.しかし場合によっては期待するほど高い精度で答は返ってこない.これは,内部処理的に高い精度で処理を続けることが不可能になり,Mathematicaが計算精度を下げて処理したため起ってしまう.もちろん,引数の有効数字を増やし,入力精度を上げておけば,Mathematicaの内部処理がより高い精度で実行できるため,多くの場合,答の精度もそれにつられて高くなる.

数値計算と桁精度
整数とその他の厳密数値要素のみで構成される式が第1の入力式であれば, N[expr, n]を使い,ほとんどの場合,指定どおり n桁精度で答を得られるであろう.ここで注意してほしいのは,高い桁精度で答を出すということは,ときには,内部の中間計算はそれ以上の精度で行われなければならない,ということである.
この中間処理で許容する補助的な有効数字を指定・変更するには,大域パラメータである $MaxExtraPrecisionの値を変えればよい.

中間計算の精度管理
Mathematicaは正しい答を得るために自動的に内部精度を上げる.
In[18]:= N[Sin[10^40], 30]
Out[18]= 
デフォルト設定の$MaxExtraPrecision=50では,Mathematicaは正しい答を出せない.
In[19]:= N[Sin[10^100], 30]

Out[19]= 
このようにしてMathematicaに,内部計算でもっと桁数を使ってもよいと指示する.
In[20]:= $MaxExtraPrecision = 200
Out[20]= 
正しい答が出せるようになった.
In[21]:= N[Sin[10^100], 30]
Out[21]= 
$MaxExtraPrecisionをデフォルト値に設定し直す.
In[22]:= $MaxExtraPrecision = 50
Out[22]= 
計算に厳密な数を使っていても,内容によっては内部処理の一部で近似値が使われることがある.このため, $MaxExtraPrecisionの設定値によっては,厳密な値を使っていても精度の低下が起る場合がある.
近似値から得られる境界値が使われ式が評価される.
In[23]:= Sin[Exp[100]] > 0
Out[23]= 
現行の $MaxExtraPrecisionの設定ではこの式は計算できない.
In[24]:= Sin[Exp[200]] > 0

Out[24]= 
$MaxExtraPrecisionの設定を臨時に変更する.今度は計算できる.
In[25]:= Block[{$MaxExtraPrecision = 100}, Sin[Exp[200]] > 0 ]
Out[25]= 
精度を低下させる計算をすると,結果の数に有効桁が全くない可能性もある.しかし,そのような場合でもなお,Mathematicaはその数の確度に関する情報を保っている.有効数字はないが確度がaである数を与えられると,Mathematicaはその数の実際の値が範囲 にあることが示せる.Mathematicaはデフォルトによりそのような数を という形で出力する.
これは20桁精度の数である.
In[26]:= x = N[Exp[50], 20]
Out[26]= 
ここには有効桁がない.
In[27]:= Sin[x]/x
Out[27]= 
それでもMathematicaは結果の確度を記録している.
In[28]:= Accuracy[%]
Out[28]= 
これを厳密な1に加えるとかなり高精度の数が与えられる.
In[29]:= 1 + %
Out[29]= 
数をその精度で特徴付ける難しさは,ゼロと一致する数ならどれでも精度がゼロであるとして扱われる点である.そのような数の既知の桁はすべてゼロなので有効であると見なしうる桁がないというのがその理由である.
これは値がゼロと一致する数である.
In[30]:= d = N[Pi, 20] - Pi
Out[30]= 
この数には精度の有効桁と見なせる桁がない.
In[31]:= Precision[d]
Out[31]= 
しかし,この数にはこの数の不確かさを特徴付ける確かな確度がある.
In[32]:= Accuracy[d]
Out[32]= 
結果がゼロ付近になりそうな計算をするときは所望の精度ではなく確度を指定した方がよいかもしれない.

確度と精度の指定
これは記号式である.
In[33]:= u = ArcTan[1/3] - ArcCot[3]
Out[33]= 
これは式がゼロに等しいことを示している.
In[34]:= FullSimplify[u]
Out[34]= 
N は結果が精度20であることを保障できない.
In[35]:= N[u, 20]

Out[35]= 
しかし確度20の結果を得ることはできる.
In[36]:= N[u, {Infinity, 20}]
Out[36]= 
任意精度の数に現れる不確定数字を扱うときに,Mathematicaは異なる2数の不確定数字は互いに完全に独立であると仮定する.その理由は追って説明するが,そうしておけば,答の精度が不正に高くなるというようなことは起らなくなる.しかし,同時に,不必要に精度を下げてしまうこともある.
特に,ある計算で2つの数が同じ処理で生成される場合には,不確定桁のうちのいくつかが同じ値を持つ可能性がある.そして,差を取ると,不確定桁が実際には消えてしまうという場合も起り得る.ところが,Mathematicaでは,不確定桁は常に独立しているという前提を取っているので,本来なら行われるべきキャンセル処理をしないという可能性もある.
20桁精度で計算する.
In[37]:= d = N[3^-30, 20]
Out[37]= 
1 + dの計算値はおよそ34桁精度である.
In[38]:= Precision[1 + d]
Out[38]= 
この値もまだ同じ精度を保っている.各々の入力変数の持つ不確定桁は独立であるという前提で計算処理を進めたからである.
In[39]:= Precision[(1 + d) - d]
Out[39]= 
数値計算アルゴリズムは,場合によっては,式中の数と数で不確定桁がキャンセルすることで答の精度を上げている.もし不確定桁がいずれキャンセルする,ということが事前に分かっているならキャンセルする不確定桁の代りに固定桁を追加しておくとよい.計算で確定桁がキャンセルすることによって,桁精度の向上した答が得られる.

精度と確度を変更する関数
dに桁10個を付け足す.
In[40]:= d = SetPrecision[d, 30]
Out[40]= 
こうすれば付け足した桁はキャンセルする.
In[41]:= (1 + d) - d
Out[41]= 
答の精度は約44桁ある.前は34桁だった.
In[42]:= Precision[%]
Out[42]= 
SetPrecisionは2進値ゼロの桁を必要数付け足すことで数の精度を上げる.ただし,計算によっては,Mathematicaが表示する桁数より多い桁を任意数導入するようになっている.そのようなときは, SetPrecisionではゼロの桁を追加する前にMathematicaが入れた桁を使う.
40桁精度の実数を作る.任意に付け足す桁は2進値ゼロとして導入される.
In[43]:= SetPrecision[0.400000000000000, 40]
Out[43]= 

大域精度管理パラメータ
$MinPrecision = nと大域定義をすることで,実効的に, SetPrecision[expr, n]で行う任意精度の設定を計算するすべてのステップに適応することができる.これは, n桁以下の有効数字を持つ任意精度の数には,全桁数が常に nになるようゼロ桁が自動的に付け足される,ということを意味している.
$MaxPrecision = nと $MinPrecision = nの両方を nに設定しておくと,任意精度の数ならどんな数でも n桁長の固定精度を持つように強制することができる.つまり, Mathematicaに,任意精度の数を機械精度の数と同じように扱うように指示することになる.もちろん,通常の機械精度より桁精度を上げてだ.
固定桁精度にすると,計算処理によっては効率が上がることがある.しかし,注意深い分析をしないと,答が出てもどの桁までが実際に正しいのか不明である.
20桁精度の小さい値を持つ数を例に取る.
In[44]:= k = N[Exp[-60], 20]
Out[44]= 
普通の計算をする.問題なく答を出してくれる.
In[45]:= Evaluate[1 + k] - 1
Out[45]= 
固定桁精度で計算するように命令する.
In[46]:= $MinPrecision = $MaxPrecision = 20
Out[46]= 
最初の数桁は正しいが残りは正しくない.
In[47]:= Evaluate[1 + k] - 1
Out[47]= 
|