1

私は現在、電卓アプリケーションを書いています。私は微分推定器をそれに書き込もうとしています。以下の式は、それを行う簡単な方法です。通常、紙の上では、最も正確な見積もりを得るために、可能な限り最小の h を使用します。問題は、double が比較的大きな数に非常に小さな数を加算することを処理できないことです。4+1E-200 などは 4.0 になります。h がちょうど 1E-16 だったとしても、実際には 4+1E16 で正しい値が得られますが、16 位以降が失われ、丸めが正しく行われないため、計算すると不正確になります。ダブルスの一般的な経験則は 1E-8 または 1E-7 だと聞いたことがあります。これに関する問題は、2E231+1E-8 が 2E23 になるため、大きな数が機能しないことです。1E-8 はサイズの問題で失われます。

f'(x)=(f(x+h)-f(x))/h as x approaches 0

ポイント 4 で f(x)=x^2 をテストすると、f'(4) は正確に 8 になるはずですが、おそらく正確に 8 になることはないことがわかりました。しかし、最も正確なのは約 1E- のようです。 7 または 1E8 面白いのは、1E-9 から 1E-11 までのすべてが同じ答えを与えることです。h のリストと の結果は次のとおりです。f(x)=x^2 at x=4

1E-7 8.000000129015916
1E-8 7.999999951380232
1E-9 8.000000661922968
1E-10 8.000000661922968
1E-11 8.000000661922968
1E-12 8.000711204658728

ここに私の質問があります:

  1. h を選択する最良の方法は何ですか。明らかに 1E-8 または 1E-7 は理にかなっていますが、x が 3.14E203 または 2E-231 であっても、任意のサイズの数値で機能するように、x に基づいて h を選択するにはどうすればよいですか.
  2. 精度の小数点以下の桁数を考慮する必要があります。
  3. TI 83、84、および Inspire は、微分を 12 桁または精度で数値的に計算でき、ほとんどの場合正しいですが、とにかくそれらの数値の最大精度は 12 桁であり、それらの計算機は非 CAS であるため、実際には何も派生していません。
  4. 論理的には、1E-7 と 1E-8 の間のどこかに数値があり、より正確な結果が得られます。その数値を見つける方法、または少なくともそれに近づく方法はありますか。

答えた

BobGさん、ありがとうございます。アプリケーションは現在、コマンド ライン PC アプリケーションの 2 つの形式になる予定です。そしてAndroidアプリ。あなたは、Aboutページの部分に特別な感謝で言及されます. もしよろしければ、オープン ソースにすることもできますが、非常に大きなバグが解決されるまで、プロジェクト サイトへのリンクは掲載しません。現時点ではMathulatorと呼んでいますが、すでに著作権があり、ばかげているように聞こえるため、名前が変更される可能性があります.リリース候補がいつ実行されるかはわかりません.安定します。しかし、必要なものをすべて実装できれば、非常に強力になります。ありがとうございます。楽しいプログラミング。

4

6 に答える 6

4

この質問に答える本があります (そして他の人も同様です):

C の数値レシピ、第 2 版、Press、Vetterling、Teukolsky、および Flannery による。この本には、C++、Fortran、および BASIC のバージョンもあります。残念ながら、Java バージョンは存在しません。さらに、この本は絶版になっていると思いますが、一部のフレーバーの中古版をオンラインで購入することができます (少なくとも bn.com を通じて)。

セクション 5.7、「数値導関数」、p. 186 では、数値導関数で発生している問題と、それが発生する理由の背後にある数学、数値導関数を適切に計算する方法の関数を正確に説明しています (C では、Java に変換するのは簡単なはずです)。簡単な概算の要約を次に示します。

1) 数値的には、対称バージョンを計算する方が良いでしょう:

f'(x) = (f(x + h) - f(x - h)) / 2h

2) h はおよそ (sigma_f)^(1/3) * x_c である必要があります

どこ

sigma_f =~単純な関数の f(x) の計算の分数精度

x_c =~ x (x がゼロでない場合)。

ただし、誤差が ~ (sigma_f)^(2/3) であるため、これは最適な導関数にはなりません。より良い解決策は、本の中で C プログラムとして提示されている Ridders のアルゴリズムです (ref. Ridders, CJF 1982, Advances in Engineering Software, vol. 4, no. 2, pp 75-76.)。

于 2011-04-04T20:39:10.447 に答える
2

1. 浮動小数点数 (float と double) の精度は、数値の絶対値に依存します。double の精度は最大 15 桁であるため、 を加算できますが、再び 10 になる可能性が高いため、 を加算する必要があり1 + 1e-15ます。意味のある結果を得るには、その 1e-8 に元の数値の絶対値を掛けることをお勧めします。これにより、導関数で約 7 桁の正しい数字が得られます。何かのようなもの:10 + 1e-1510 + 1e-14

double h = x * 1e-8;
double derivative = (f(x+h) - f(x)) / h;

とにかく、これは近似値です。たとえば、x=1e9 で sin(x) の導関数を計算しようとすると、h=10 になり、結果はすべて間違ったものになります。しかし、ゼロに近い「興味深い」部分を持つ「通常の」関数の場合、これはうまく機能します。

2.「h」が小さいほど、導関数をサンプリングするポイントがより正確になりますが、得られる導関数の正しい桁数は少なくなります。これを証明することはできませんが、15 がの精度である正しい数字がh = x * 1e-8得られるというのが私の直感です。7 = 15 - 8double

また、「より対称的な」式を使用することをお勧めします。これにより、2 次多項式で絶対に正しい答えが得られます。

double derivative = (f(x+h) - f(x-h)) / (2*h);
于 2011-04-04T20:43:03.220 に答える
2

「すべてのプログラマーが浮動小数点について知っておくべきこと」というタイトルの論文を読んでください (Google で検索してください)。次に、ほとんどの浮動小数点値がコンピューター ハードウェアで近似的に表現されていることがわかります。

この欠点のない計算を行うには、シンボリック計算を使用します。しかし、これは浮動小数点を使用するほど効率的ではありません。

浮動小数点の結果に一貫性を持たせるには、0.1、0.01 などのように、最も近い 10 のべき乗に丸めます。近似をいつ停止する必要があるかを理解するには、近似ステップで監視する何らかのしきい値を使用します。たとえば、次の近似ステップを実行しても、既に計算された値に対して 0.001% しか変化しない場合、近似を続ける意味はありません。

更新私はずっと前に数値計算クラスを持っていましたが、数値が非常に近い場合、最も信頼できる数字が相殺され、信頼できない数字があるため、近い数字を減算することは非常に悪いことを漠然と思い出すことができます. これはまさに を減らすときに起こることですh。これらの状況で提案されているのは、他の操作で減算を代用することです。たとえば、`f(x) が展開されるある種の系列に切り替えることができます。

答えはあなたの要件に依存するため、2番目の質問はよくわかりません-「好きなだけ」。

ところで、math.stackexchange.com で質問に対する回答を見つけることができれば、運が良いかもしれません。

さらに、提供されたリンクにアクセスしてくださいthrashgod:数値微分

于 2011-04-04T20:19:31.520 に答える
1

私の質問は、最も適切なhとは何か、どのように任意のサイズにスケーリングできるかです。

数値微分で述べたように、 hの適切な選択はsqrt(ɛ) * xです。ここで、ɛマシンのイプシロンです。

于 2011-04-04T20:49:03.950 に答える
0

Javadoc によると、11 ビットは指数を表し、52 ビットは有効数字を表します。指数を無視すると、52ビットで遊ぶことができるようです。したがって、h = x * 2^-40 を選択すると、ここで 40 ビットを使用したことになり、表示される精度は 2^-12 になります。この比率を必要に応じて調整します。

于 2011-04-04T20:44:39.087 に答える
0

このような計算にはBigDecimalクラスを使用しますが、質問への回答ではありませんが、浮動小数点演算の精度が本当に向上します。

于 2011-04-04T20:22:08.073 に答える