合計 昨日 今日

e^2xをマクローリン展開する

フォーラムルール
フォーラムルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Name: t_n_y_09
[URL]
ぴよぴよ(111 ポイント)
Date: 2017年5月17日(水) 11:43
No: 1
(OFFLINE)

 e^2xをマクローリン展開する

大学の課題が解けません。
デバッグはできるのですが数字が合いません。
どこが違うか教えてください。

問題
e^2xをマクローリン展開し、有効数字10桁まで求めよ。


この時の有効数字は、展開したk-1の項までの和と、k項までの和が10桁一致するまでループするということです。
k項までの和-k項までの和は、k項であると思ったので、k項×10^10が0以下になるまでループしました。

コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#define _CRT_SECURE_NO_WARNINGS 1
#define _USE_MATH_DEFINES
#include<stdio.h>
#include <math.h>
 
int main(void) {
    double x;
    int kai = 1;
    int k;
    int i;//階乗に使う
    double bb;//2*x
    double bb2;//分母
    double kou;//k項
    double ans;//2項からk項までの和
    double sa;//最後の項
 
    printf("e^2xのxをいくつにしますか?\n");//e^2xの入力
    scanf("%lf", &x);
    bb = 2 * x;
    ans = 1.0;
    for (k = 1;; k += 1)//kを増やす
    {
        bb2 = pow(bb, k);//2x^k
        for (i = 1; i <= k; ++i) {//階乗
            kai = kai * i;
        };
 
        kou = bb2 / kai;//k項
        sa = kou * 10000000000;
 
        if (sa <= 0)
            break;//差が0以下になったらこのループを終わりにする。
 
        ans = ans + kou;
    }
printf("計算結果は%fです\n", ans);//出力⑨
 
    return 0;
}


[実行結果]
e^2のxを何にしますか?
5(入力)
計算結果は182.000927です

Name: かずま
[URL]
Date: 2017年5月17日(水) 15:57
No: 2
(OFFLINE)

 Re: e^2xをマクローリン展開する

t_n_y_09 さんが書きました:デバッグはできるのですが数字が合いません。
どこが違うか教えてください。

bb2 = pow(bb, k); を
bb2 = pow(bb, 2 * k); にする。

別解
コード[C]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
 
int main(void)
{
    double x;
    while (printf("x: "), scanf("%lf", &x) == 1) {
        double y = 1, t = 1;
        for (int k = 1; y != y - t; k++)
            y += t *= 2 * x / k;
        printf("%.15g\n", y);
    }
    return 0;
}

Name: かずま
[URL]
Date: 2017年5月17日(水) 16:27
No: 3
(OFFLINE)

 Re: e^2xをマクローリン展開する

かずま さんが書きました:bb2 = pow(bb, k); を
bb2 = pow(bb, 2 * k); にする。

すみません。この指摘は間違いです。
(2 * x) を k乗しないといけないのにしていないなあ、と勘違いしました。
bb が (2 * x) だったんですね。
終了条件がおかしいようなので、もう少し調べてみます。

Name: かずま
[URL]
Date: 2017年5月17日(水) 16:36
No: 4
(OFFLINE)

 Re: e^2xをマクローリン展開する

kai がオーバーフローしています。
int kai = 1; を double kai; にしてください。

kai の初期化は、for文で行います。
for (kai = k = 1; ; k++)

終了条件は、if (ans + kou == ans) break; です。
kou は ゼロにはなりませんが、かなり小さくなります。
すると、ans + kou で桁落ちして、結果が ans になります。
sa は不要です。

Name: みけCAT
[URL]
伝説なるハッカー(655,393 ポイント)
Date: 2017年5月17日(水) 22:26
No: 5
(OFFLINE)

 Re: e^2xをマクローリン展開する

しまった、二重投稿でしたか。
e^2xをマクローリン展開する • C言語交流フォーラム ~ mixC++ ~
みけCAT さんが書きました:
  • 各繰り返しにおいて、kaiに1からkまでの整数全てを掛けるのではなく、kだけを掛ける
  • kaiの型をintからdoubleにする
という変更を加えた所、x=5の時の計算結果が合いました。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Name: みけCAT
[URL]
伝説なるハッカー(655,393 ポイント)
Date: 2017年5月17日(水) 22:28
No: 6
(OFFLINE)

 Re: e^2xをマクローリン展開する

かずま さんが書きました:kai の初期化は、for文で行います。
for (kai = k = 1; ; k++)

それはなぜですか?
宣言時のみに初期化をしても、間違いではないでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Name: かずま
[URL]
Date: 2017年5月18日(木) 00:26
No: 7
(OFFLINE)

 Re: e^2xをマクローリン展開する

みけCAT さんが書きました:
かずま さんが書きました:kai の初期化は、for文で行います。
for (kai = k = 1; ; k++)

それはなぜですか?

すみません。修正方法の書き方に間違いがありました。

for文は、for (k = 1; ... と for (i = 1; ... の 2つあって、
後者を for (kai = i = 1; 修正するのですが、
回答を書くとき、間違って for (kai = k = 1; と
書いてしまいました。正しくは、24行目を
for (kai = i = 1; i <= k; ++i) {//階乗
にする、です。

みけCAT さんが書きました:宣言時のみに初期化をしても、間違いではないでしょう。

kai の宣言は main の最初のほうにありますが、
第k項の kai を求める for文で初期化しないと、
第(k-1)項の kai にさらに k の階乗を掛けることになって
間違った結果になります。

Name: みけCAT
[URL]
伝説なるハッカー(655,393 ポイント)
Date: 2017年5月18日(木) 00:29
No: 8
(OFFLINE)

 Re: e^2xをマクローリン展開する

かずま さんが書きました:
みけCAT さんが書きました:宣言時のみに初期化をしても、間違いではないでしょう。

kai の宣言は main の最初のほうにありますが、
第k項の kai を求める for文で初期化しないと、
第(k-1)項の kai にさらに k の階乗を掛けることになって
間違った結果になります。

自分が書いたように、変数宣言の所で初期化をしてkのループ内ではkaiにkの階乗ではなくkを掛けるようにすることで、
正しい結果を得つつ、毎回階乗を計算するよりステップ数を減らすことができます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Name: かずま
[URL]
Date: 2017年5月18日(木) 02:21
No: 9
(OFFLINE)

 Re: e^2xをマクローリン展開する

みけCAT さんが書きました:自分が書いたように、変数宣言の所で初期化をしてkのループ内ではkaiにkの階乗ではなくkを掛けるようにすることで、
正しい結果を得つつ、毎回階乗を計算するよりステップ数を減らすことができます。

第k項は (2x)k / k! です。
質問者の t_n_y_09さんは、これをそのままコード化しようとしたんでしょう。
コード[C]: 全て選択
1
2
3
4
5
    bb = 2 * x;
    for (k = 1; ; k += 1) {
        bb2 = pow(bb, k);
        kai = factorial(k);
        kou = bb2 / kai;

階乗の関数 factorial はないから、forループを使った。

みけCATさんは、一つ前の項の計算で使用した kai を使えば
ステップ数が減らせるとして、次のようにした。
コード[C]: 全て選択
1
2
3
4
5
6
    double kai = 1;
    bb = 2 * x;
    for (k = 1; ; k += 1) {
        bb2 = pow(bb, k);
        kai *= k;
        kou = bb2 / kai;

それなら、pow も使わないほうが良いでしょう。
コード[C]: 全て選択
1
2
3
4
5
6
7
    double bb2 = 1;
    double kai = 1;
    bb = 2 * x;
    for (k = 1; ; k += 1) {
        bb2 *= bb;
        kai *= k;
        kou = bb2 / kai;

さらに、次のようにすることができます。
コード[C]: 全て選択
1
2
3
4
    double kou = 1;
    bb = 2 * x;
    for (k = 1; ; k += 1) {
        kou *= bb2 / k;

私は、最初の回答の別解でこれを示しました。
コード[C]: 全て選択
1
2
3
    double y = 1, t = 1;  // y は元の ans。t は term(項) で、元の kou
    for (int k = 1; y != y - t; k++)
        y += t *= 2 * x / k;  // 2 * x は bb のように一つの変数にしたほうがよいかな?

終了条件を、t がゼロになるまでとすると、k = 171 になります。
y が一つ前の y と等しくなるまでとすると、k = 46 になって、
ステップ数が大きく減少します。x = 5 の場合ですが。

Name: かずま
[URL]
Date: 2017年5月18日(木) 14:20
No: 10
(OFFLINE)

 Re: e^2xをマクローリン展開する

かずま さんが書きました:さらに、次のようにすることができます。
コード[C]: 全て選択
1
2
3
4
    double kou = 1;
    bb = 2 * x;
    for (k = 1; ; k += 1) {
        kou *= bb2 / k;

すみません。最後の行は kou *= bb / k; の間違いです。

t_n_y_09 さんが書きました:問題
e^2xをマクローリン展開し、有効数字10桁まで求めよ。

有効数字10桁ですから、
コード[C]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#define _CRT_SECURE_NO_WARNINGS 1
#define _USE_MATH_DEFINES
 
#include <stdio.h>
#include <math.h>
 
int main(void)
{
    int k;
    double x;        // 入力
    double kai = 1;  // k! (k の階乗。第k項の分母)
    double bb;       // 2*x
    double bb2 = 1;  // (2*x)^k (第k項の分子)
    double kou;      // 第k項
    double ans = 1;  // 第k項までの和
 
    printf("e^2xのxをいくつにしますか?\n");
    scanf("%lf", &x);
    bb = 2 * x;
    for (k = 1; ; k++) {
        bb2 *= bb;
        kai *= k;
        kou = bb2 / kai;
        ans += kou;
#if 0
        printf("%3d: bb2=%6g, kai=%-12g, kou=%-12g, ans=%-19.18g\n",
                k, bb2, kai, kou, ans);
#endif
        if (kou * 1e10 < ans) break;
    }
    printf("計算結果は %.10g です\n", ans);
    return 0;
}

#if 0 を #if 1 にすると、デバッグ表示が出ます。

Name: かずま
[URL]
Date: 2017年5月26日(金) 06:58
No: 11
(OFFLINE)

 Re: e^2xをマクローリン展開する

No.10 のプログラムでは、x = 45.53 までは大丈夫ですが、
それを超えるとbb2 が浮動小数点の最大値を超え、
無限ループになるようです。

次のようにすると、x = 354 まで大丈夫で、それを超えても
結果が無限大になるだけで、無限ループにはなりません。
コード[C]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
 
int main(void)
{
    double x;
    puts("e^2xのxをいくつにしますか?");
    if (scanf("%lf", &x) != 1) return 1;
    double sum = 1, term = 1, x2 = 2 * x;
    for (int k = 1; term * 1e10 > sum; k++)
        sum += term *= x2 / k;
    printf("計算結果は %.10g です\n", sum);
    return 0;
}

pow を使わないので、#include <math.h> は要りません。

質問者は、なぜ返信してこないのだろうか?


Return to C言語何でも質問掲示板

オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[6人]