23JON
@23JON (23 JON)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

ラマヌジャンの式をプログラミング

Q&A

数理の問題をプログラミングしてみようと思って、ラマヌジャンの式をプログラムしたのですが、コアダンプが出力されてしまいました。

ちなみに、今回プログラムしたいと思った問題は、4/π(=3.1415...)の近似値を調べるもので、試行回数が多いほど数値が期待しているものに限りなく近くなるというものです。
(以下「式」より、試行回数が∞回に近ければ近いほど、数値は4/πに近くなるということ。)
(式)
image.png

<プログラム>

#include <stdio.h>
#include <math.h>

int fact(int n)
{
   return n*fact(n-1);
}

double sum(int n)
{
   int i;
   double s;
   s=0.0;
   for(i=0;i<n;i++){
    s=s+(pow(-1,i)*fact(4*i)*(1123+21460*i))/(pow(882,2*i+1))*(pow((pow(4,i)*fact(i)),4));
   }
   return s;
}

int main(void)
{
   int i,n;
   printf("ラマルジャンの公式を利用して、4/πの値を出力します。\n");
   printf("試行回数は: "); scanf("%d",&n);

   printf("値は%f\n",sum(n));
   return 0;
}

実行結果

~/suuri$ ./a.out
ラマルジャンの公式を利用して、4/πの値を出力します。
試行回数は: 23
Segmentation fault (コアダンプ)

なぜコアダンプが出力されたのかよくわからなかったので、修正点があればご指摘いただけるととても助かります。

0

3Answer

単にfact関数の再帰停止条件がないから・・・かなぁ
再帰停止条件ないから引数の値がマイナス限界突破してそう

0Like

だいぶ前の投稿に対してのコメントになることをご容赦ください。

根本的な原因はktz_aliasさんのご指摘の通り、再帰の終了条件がないことです。

しかし、Segmentation faultになる理由は、型の上限とは関係ありません。
無限再帰呼び出しをしているため、そもそもfact関数が値を返すことはないはずです。
再帰呼び出しのし過ぎでスタックを使い果たしたのではないでしょうか。

例えば、下記のコードを実行するfact(int n)関数は一度も値を返さず強制終了していることが分かります。(Wandboxで実行)

#include <stdio.h>
#include <math.h>

int fact(int n)
{
    if( n > 0 || n % 1000 == 0){
        printf("fact(%d) が呼ばれた\n", n);
    }
    return n*fact(n-1);
}

double sum(int n)
{
    int i;
    double s;
    s = 0.0;
    for(i = 0; i<n; i++){
        printf("%d回目 演算前\n", i);
        s = s + (pow(-1,i)*fact(4*i)*(1123+21460*i))/(pow(882,2*i+1))*(pow((pow(4,i)*fact(i)),4));
        printf("%d回目 演算後\n", i);
    }
    return s;
}

int main(void)
{
    int i,n;
    printf("ラマルジャンの公式を利用して、4/πの値を出力します。\n");
    //printf("試行回数は: ");
    // scanf("%d",&n);
    // 毎回入力が面倒なので、検証用に若干変更
    n = 10; 
    printf("試行回数は: %d\n", n);

    printf("値は%f\n",sum(n));
    return 0;
}

先ほど紹介した記事のタイトルにあるように、こういう場合は再帰呼び出しではなくループで実装すると安全だと思いますよ。(Wandboxで実行)

#include <stdio.h>
#include <math.h>

int fact(int n)
{
    /*
    if( n > 0 || n % 1000 == 0){
        printf("fact(%d) が呼ばれた\n", n);
    }
    */
    
    int factorialN = 1;
    for(int i = 1; i <= n; i++) {
        factorialN *= i;
    }
    return factorialN;
}

double sum(int n)
{
    int i;
    double s;
    s = 0.0;
    for(i = 0; i<n; i++){
        // printf("%d回目 演算前\n", i);
        s = s + (pow(-1,i)*fact(4*i)*(1123+21460*i))/(pow(882,2*i+1))*(pow((pow(4,i)*fact(i)),4));
        // printf("%d回目 演算後\n", i);
    }
    return s;
}

int main(void)
{
    // fact(int n) の動作確認用コード
    for(int i = 0; i < 10; i++){
        printf("%d! = %d\n", i, fact(i));
    }
    puts("");
    
    int i,n;
    printf("ラマルジャンの公式を利用して、4/πの値を出力します。\n");
    //printf("試行回数は: ");
    // scanf("%d",&n);
    // 毎回入力が面倒なので、検証用に若干変更
    n = 10; 
    printf("試行回数は: %d\n", n);

    printf("値は%f\n",sum(n));
    return 0;
}

0Like

Comments

  1. @23JON

    Questioner

    回答ありがとうございます。
    とても参考になりました。

Your answer might help someone💌