0

マクローリン シリーズを使用して cosh(x) ans sin(x) を評価する必要がある宿題をしています。プログラムが実行されるたびに、ユーザーは 0 ~ 10 の数字を入力して、シリーズを評価する用語の数も指定します。次に、評価する x の値を入力します。ユーザーが Enter キーを押すと、シリーズの 10 個の増分が計算され、出力されます。さらに、正確なエラーも見つけなければなりません。これを行うために、特定の項の計算を実行する、sinh と cosh の両方に対していくつかの異なる関数を作成しました。例: 以下のコードは、用語を 10! まで評価します。

void cosFunction10(double power, double value)
{
     double cosh_x = 0;
     double math_cosh = 0;
     double exact_error;
     double x;

     if (value < 0)
         x = -0.1*0;

     for (int i = 0; i < 11; ++i)
     {
         cosh_x = (1.0 + ((x*x)/(2.0*1.0)) + ((x*x*x*x)/(4.0*3.0*2.0*1.0)) + ((x*x*x*x*x*x)/(6.0*5.0*4.0*3.0*2.0*1.0)) + ((x*x*x*x*x*x*x*x)/(8.0*7.0*6.0*5.0*4.0*3.0*2.0*1.0)) + ((x*x*x*x*x*x*x*x*x*x)/(10.0*9.0*8.0*7.0*6.0*5.0*4.0*3.0*2.0*1.0)));
         math_cosh = cosh(x);
         exact_error = (math_cosh - cosh_x);

         cout << setiosflags(ios::scientific) << setprecision(3) << x << "\t";
         cout << setiosflags(ios::scientific) << setprecision(5) << cosh_x << "\t";
         cout << math_cosh << "\t";
         cout << exact_error << endl;
         x = x + (0.1*value);
     }
 }

プログラムを実行して、10 (n 番目の項) と -6 (x の値) の値を入力するとします。

これは私が得るべきものです: (2番目のインクリメント)

 x                Series            Exact (using the cmath functions)    Exact % Error
 -6.000e-001      1.18547e+000      1.18547e+000                        0.00000e+000

次の 2 つの出力は、4 番目のインクリメントに到達するまで、正確なエラーに対して同じになります。

 x                Series            Exact (using the cmath functions)    Exact % Error
 -1.800e+100      3.10747e+000      3.10747e+000                        -7.67243e-005

コードを実行すると、上記の結果が得られません: (2 回目のインクリメント)

 x                Series            Exact (using the cmath functions)    Exact % Error
-6.000e-001      1.18547e+000      1.18547e+000                         4.55325e-012

私の正確なエラーは、私が与えられたものと同じでさえないため、何かがうまくいかないようです。多少異なる値が存在する可能性があることは理解していますが、これは予想されることですが、この程度ではありません。

どんな提案でも大歓迎です、

ありがとうございました

4

5 に答える 5

4

cosh(x)は以下の式に従って異なる方法で定義されているため、このような違いがあるに違いありません。

ここに画像の説明を入力

詳しくはこちらをご覧ください。

ただし、MacLaurin 級数の計算に基づいて金額を計算している場合、問題は正しい方法で値を累積していないことです。以下の実装は、おそらく実際に必要なものです。

void cosFunction(double x)
{
    double cosh_x = 1;
    double math_cosh;
    double exact_error;
    double factorial = 1;
    double x_pow = 1;

    for (int i = 0; i < 11; ++i) {
            cosh_x = x_pow/factorial;
            x_pow = x*x*x_pow; 
            factorial = factorial* (2 * i + 1) * (2 * i + 2);
    }

    math_cosh = cosh(x);
    exact_error = (math_cosh - cosh_x);
    cout << setiosflags(ios::scientific) << setprecision(5) << exact_error << endl;

}
于 2012-10-13T03:50:02.350 に答える
1

正解は、数学的な意味ではゼロかもしれません。しかし、実際のコンピューティングの意味では、ゼロにはなりません。

固定の小数精度、たとえば8桁で算術演算を実行している場合を想像してみてください。1.0/3.0として表します.33333333。しかし、それはどちらになるかという3.0 * (1.0/3.0)こと3.0 * .33333333になります.999999999。したがって、数学的な意味で1.0 - (3.0 * (1.0 / 3.0))は、小数点以下の精度が固定されたゼロである必要がありますが、のようなものが得られる可能性があります.00000001

同じルールが固定バイナリ精度にも適用されます。これは、を使用したときに得られるものですdouble

于 2012-10-13T05:26:19.033 に答える
1

コメントで明らかになったように、実際に得られるエラーは非常に小さく、10 -11未満です。さらに、cosh の計算方法と組み込み関数による計算方法がまったく同じではないことを考慮する必要があります。どちらの方法も最終的には近似ですが、異なる方法で機能するため、生成される丸め誤差と近似誤差はわずかに異なります。

エラーが「フラット 0」になることは期待できません。

于 2012-10-13T04:13:19.647 に答える
1
//Part of the problem is that in the line after the 'for' nothing changes (typo?.) The
//following works for x = 0.5`
//Note that the loop works properly for all terms including the first which is 1.0

#include <iostream>
#include <math.h>

using namespace std;

int factorial(int n)
{
    return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
}

int main()
{
    // use taylor series to approximate cosh(x) - use 7 terms
    double x = 0.5;
    double top, bot;
    double s = 0.0;

    for (int i = 0; i < 7; i++)
    {
        top = pow(x,double(i)*2.0);
        bot = double(factorial(i*2));
        s  += (top / bot);
    }
    cout << "myCosh     " << s << endl;
    cout << "cosh       " << cosh(x)<< endl;
    cout << "difference " << fabs(s - cosh(x)) << endl;
    return 0;
}
于 2012-10-13T06:12:19.350 に答える
0

cout次のように操作を変更して関数を実行しました。

cout << setiosflags(ios::fixed) << setprecision(12);
cout << "for x="<<x<<": "<<math_cosh<<" - "<<cosh_x<<" = "<<exact_error<<"\n";

value何を使用していたかを示していないため、 に独自の値を選択しました。

次の結果が得られます。これは、math_coshと が同じでcosh_xないことを示しています。あなたの問題は、数字が異なっていることに気付くのに十分な数字が表示されなかったことのようです。

for x=0.003233200000: 1.000005226796 - 1.000005226791 = 0.000000000005
for x=0.006466400000: 1.000020907237 - 1.000020907164 = 0.000000000073
for x=0.009699600000: 1.000047041489 - 1.000047041120 = 0.000000000369
for x=0.012932800000: 1.000083629824 - 1.000083628658 = 0.000000001166
for x=0.016166000000: 1.000130672624 - 1.000130669778 = 0.000000002846
for x=0.019399200000: 1.000188170381 - 1.000188164480 = 0.000000005901
for x=0.022632400000: 1.000256123697 - 1.000256112765 = 0.000000010932
for x=0.025865600000: 1.000334533282 - 1.000334514632 = 0.000000018650
for x=0.029098800000: 1.000423399955 - 1.000423370081 = 0.000000029875
for x=0.032332000000: 1.000522724646 - 1.000522679112 = 0.000000045534
for x=0.035565200000: 1.000632508392 - 1.000632441726 = 0.000000066667

宿題の割り当てに関しては、マクローリン級数を使用して cosh(x) を計算します。関数は、書かれているように、級数の最初の 3 つの項のみを計算するため、あまり正確ではありません1 + 0 + x*x/2。x^n または n を計算していません! n=2 を超えています。より正確な結果を生成するには、次のように、級数のより多くの項を蓄積する必要があります...

int NUMBER_OF_TERMS=10; // the number of terms to compute (including zero terms)
for ( int i=0; i<NUMBER_OF_TERMS; i++ )
   {
   cosh_x += (i%2==0?1:0)*term; // even derivatives are 1, odd derivatives are 0
   term *= x/(i+1); // apply incremental power and factorial
   }

これはまだ正確性を保証するものではありません。丸め誤差のため、アルゴリズムを正確に複製しない限り、組み込み関数 cosh(x) を完全に一致させることはできません。ほとんどの入力値では、純粋な数学的出力は超越数になるため、両方の関数は近似値のみを生成します。そのような数はdouble.

また、マクローリン級数は多項式ベースの近似であり、 付近で最も正確であることに注意してくださいx=0。多項式の性質と同様に、不完全な合計は最終的に (x が 0 から遠ざかるにつれて) 正しい答えから非常に急速に発散する可能性があります。これが、上記の出力例で、 の値が小さいほどエラー値が小さい理由ですx


指数表記と固定小数点精度について:

科学表記法では、数字の最上位のゼロ以外の数字が表示されます。それらの数字が小数点の 12 桁目から始まる場合でも同様です。科学表記法を読むときは、 の後の情報に注意することが重要eです。これは数値の真の大きさを表しているからです。 double- 精度値には、10 進数で約 20 桁の実際の情報を格納できます。これは、多くの繰り返し計算を行う場合には便利ですが、通常、2 つの数値が等しいかどうかを比較する場合にはあまり意味がありません。

これは課題の範囲内ではないかもしれませんが、できることは、差の固定小数点精度を制限することです。これを行う方法の例を次に示します。

const double PRECISION=1e-4; // indicates the number of fractional digits to keep
exact_error = round(exact_error/PRECISION)*PRECISION; // limit precision

...または、ゼロに近いケースをチェックする方が簡単かもしれません...

if ( fabs(exact_error)<PRECISION/2 ) exact_error = 0; // close enough to zero
于 2012-10-13T04:36:01.840 に答える