4

大きくて負の実数を扱うときに、次の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

どんな支援も大歓迎です、乾杯。

編集:

わかりましたので、質問は次のとおりです。

このコードが近似する数学関数はどれですか? (指数関数と言います。) x = 1 のときはうまくいきますか? (はい。)残念ながら、x = -100 のときにこれを使用すると、答えは s = 8.7364e+31 になります。あなたの同僚は、プログラムにばかげたバグがあると信じており、あなたの助けを求めています。動作を注意深く説明し、より良い結果が得られる簡単な修正を行います。[上記のコードの変更を提案するか、それを使用する必要があります。簡単な修正が機能することも確認する必要があります。]

したがって、用語間に16桁(またはそれ以上)の桁数がある場合、問題が大きな数を取り囲み、精度が失われることをある程度理解していますが、解決策はわかりません。

ありがとう

編集:

だから最後に私はこれで行きました:

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-
044s = 3.722053303838800e-044

さらに分析した後 (そして残念ながら課題を提出した後)、反復回数を増やして項を増やすと、効率がさらに向上することに気付きました。実際、次の方法はさらに効率的でした。

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
秒 = 3.720075976020701e-044

4

2 に答える 2

7

ジョンがコメントで指摘しているように、ループ内にエラーがあります。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 の場合にのみ急速に収束する必要のある級数まで減らすことができます。

編集: 同じ ID のバリエーションを使用して範囲削減を行うことができる 2 つ目の方法があります。

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

したがって、大きな数、おそらく 12.8 の指数を計算したいとします。これを許容できる速さで収束させるには、単純な級数で多くの項が必要になり、大量の減算キャンセルが発生するため、いずれにしても良い精度は得られません。しかし、それを認識した場合、

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

次に、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

このような方法を使用して範囲縮小を行うときはいつでも、追加の計算が必要なために数値的な問題が発生する可能性がありますが、通常、シリーズの収束が大幅に強化されているため、はるかに先に進むことに注意してください。

于 2012-04-23T13:33:41.283 に答える
5

なぜそれが間違った答えだと思いますか。その数列の最後の項とサイズを見て、0 に近い答えが得られると予想する理由を教えてください。

私の最初の回答では、丸め誤差が問題であると述べていました。これはこの基本的なアプローチでは問題になりますが、適切な数学的(コンピューターの浮動小数点演算ではなく) 答えを得るには 40 項で十分だと思うのはなぜですか。

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

Woodchip は、射程距離の縮小について正しい考えを持っています。これは、これらの種類の機能を非常に迅速に実装するために人々が使用する典型的なアプローチです。すべてを理解したら、ループ内の隣接する項を合計し、k = 1 : 2 : 40 (たとえば) でステップすることにより、交互シーケンスの丸め誤差を処理します。x = -100 の場合、被加数は非常に長い間増加するため、木材チップのアイデアを使用するまで、これは機能しません。|x|が必要です < 1 は、中間項が縮小していることを保証するため、書き換えが機能します。

于 2012-04-23T13:18:51.127 に答える