2012-04-23 131 views
4

大小の実数を扱うときに、以下のMatlabコードを指数関数近似で近似させる方法を知っている人はいますか?指数関数を近似するMatlabコード

たとえば、x = 1の場合、コードはうまく動作し、x = -100の場合、3.7201e-44に近いときは8.7364e + 31の回答が返されます。

s=1 
a=1; 
y=1; 
for k=1:40 
    a=a/k; 
    y=y*x; 
    s=s+a*y; 
end 
s 

どのような援助が理解され、歓声次のよう

コードです。

EDIT:

[OK]を次のように質問があるので:

数学関数は、このコードは、おおよそのないものはどれか(私は指数関数と言っています) x = 1のときに機能しますか? (はい。)残念ながら、x = -100のときにこれを使用すると、答えはs = 8.7364e + 31になります。あなたの同僚は、プログラムにばかげたバグがあると考えて、あなたの援助を求めます。注意深く行動を説明し、よりよい結果を生み出す簡単な修正を与える。 [上記のコードを修正するか、それを使用することを提案する必要があります。また、あなたの簡単な修正作品をチェックする必要があります。]

をだから私は、多少の精度が失われ、用語間の大きさの16(またはそれ以上)の注文があった場合に問題が大きな数字を取り囲んでいることを理解しますが、解決策は私を見逃さ。

おかげ

EDIT:

だから最後に、私はこれと一緒に行きました:それは完全に正しいのですが、それはいくつかの良い近似値を返す場合

s = 1; 
x = -100; 
a = 1; 
y = 1; 
x1 = 1; 

for k=1:40 
    x1 = x/10; 
    a = a/k; 
    y = y*x1; 
    s = s + a*y; 
end 

s = s^10; 
s 

わかりません。

さらなる分析の後EXP(-100)= 3.720075976020836e-044
S = 3.722053303838800e-044

(残念ながら割り当てを提出)、Iは、反復回数を増加させるので、用語を増加実現効率をさらに向上させる。実際には以下がさらに効率的であった:

s = 1; 
x = -100; 
a = 1; 
y = 1; 
x1 = 1; 

for k=1:200 
    x1 = x/200; 
    a = a/k; 
    y = y*x1; 
    s = s + a*y; 
end 

s = s^200; 
s 

与える:

EXP(-100)= 3.720075976020836e-044
S = 3.720075976020701e-044

+1

y = x^kとすると思いますか?またはy = y * x?コードは、a * yという用語は常に(丸め誤差を無視して)1です。 – John

+0

ありがとうございます。うん、それはy = y * xであるはずのタイプミスです。 –

答えて

7

Johnがコメントで指摘したように、ループ内にエラーがあります。 y = y * k行は必要なことをしません。 exp(x)のシリーズの用語をもっと注意深く見てください。

とにかく、このようなシリーズが大きな値のために非常によく収束しないことを知るために、この宿題が与えられたのはこのためです。代わりに、範囲の縮小を行う方法を検討する必要があります。

はたとえば、あなたはあなたの利点に身元

exp(x+y) = exp(x)*exp(y) 

を使用することができますか? exp(1)= 2.7182818284590452353の値を格納するとします。

ここで、exp(1.3)の値を計算するよう依頼したら、上記の情報はどのように使用しますか?

exp(1.3) = exp(1)*exp(0.3) 

しかし、すでにexp(1)の値を知っています。実際、ちょっと考えてみると、指数関数の範囲を縮小して、abs(x)< = 0.5の場合にのみ、急速に収束する必要があります。

編集:同じアイデンティティのバリエーションを使用して範囲を縮小できるもう1つの方法があります。

exp(x) = exp(x/2)*exp(x/2) = exp(x/2)^2 

したがって、おそらく12.8の大きな指数を計算したいとします。これを許容範囲内で高速に収束させるには、シンプルなシリーズでは多くの用語が使われますが、減法的な取り消しが多発するため、とにかく正確な精度を得ることはできません。しかし、我々はあなたが効率的に0.8の指数を計算することができれば

12.8 = 2*6.4 = 2*2*3.2 = ... = 16*0.8 

が、その後、その後、目的の値が、おそらく繰り返し二乗により、回復することは容易であることを認識した場合。

exp(12.8) 
ans = 
      362217.449611248 

a = exp(0.8) 
a = 
      2.22554092849247 
a = a*a; 
a = a*a; 
a = a*a; 
a = a*a 
      362217.449611249 

exp(0.8)^16 
ans = 
      362217.449611249 

あなたはこのようなメソッドを使用して、範囲縮小を行うたびに必要な追加の計算による数値的な問題が発生する可能性がありながら、あなたは通常、原因あなたのシリーズの大幅に強化収束への道先に出てくることに注意してください。

+0

Woodchipsに感謝します。アルゴリズムにこれをどのように適用するかはわかりません。特にx = -100の場合は特にそうです。 –

+1

-100/2とは何ですか? –

+0

exp(hpf(-100)) ans = 3.720075976020835962959695803863118337358892292376781967120613876663290475895815718157118778642281497e-44 –

5

なぜだと思いますがそれは間違った答えですか?そのシーケンスの最後の項を見て、それは大きさで、なぜ0に近い答えが必要なのかを教えてください。

私の元の答えは丸め誤差が問題であると述べました。そのになりますが、なぜ40は適切なの数学的な(コンピュータの浮動小数点演算とは対照的に)の答えで十分だと思いますか?

100^40/40! 〜= 10^31。

ウッドチップは、範囲の削減と適切なアイデアを持っています。これは、人々がこれらの種類の機能を非常に迅速に実装するために使用する典型的なアプローチです。すべてが解かれたら、交互シーケンスの丸め誤差を処理し、ループ内の隣接する項を合計し、k = 1:2:40(例えば)でステッピングします。 x = -100の場合、summandsはの間で非常にと長くなるので、woodchipsのアイデアを使用するまでここでは機能しません。あなたは| x |が必要です<中間項が縮小していることを保証するために1、したがって書き換えが機能します。

+1

まあ、丸めはそれを見る一つの方法ですが、実際にはそうではありません。関連するフレーズは「大量減算」である。非常に大きな負の値があり、シリーズの用語としては非常に大きな正の値があります。 2つは理論的には、あなたが多くの用語を持っているなら、最終的に相殺することになります。実際には、浮動小数点演算の限界によって精度が失われるため、これは起こりません。これは、プロセスが大量減算解除として知られている理由です。 –

+0

あなたがコメントしたときに私は書き直していました。面白い。 – John

+0

はい、良いタイミングです。私はそこにコメントを残しておきます。なぜなら、大量減算のコンセプトが重要なものだからです。 –