見出し画像

プログラミング学習の記録 #010(C)

ミールを利用してコーヒー牛乳を飲んでいたのだが、さすがに毎日飲んでいると飽きてくるし、無駄遣いのような気もしてくる。そこで、下宿で余っていた紅茶バッグを使って紅茶を入れることにした。元々、紅茶は好きだったが、いれるのが面倒であまり飲んでいなかった。節約と変化のために、しばらく紅茶を飲もうと思う。もちろん、アイスティーである。

前回の復習(続き)

練習問題 6.5

2個の自然数を入力し、その2個の自然数の最大公約数(2個の数の共通の約数で最も大きいもの)を求めるプログラムを作成せよ。

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

int main()
{
    int i, j, max;

    printf("Input the number of integers you have: "); //How many integers you have?
    scanf("%d", &max);
    if(max < 1)
    {
        printf("Error in this number.\n");
        exit(1);
    }

    int x[max] ;

    for(i=1; i <= max; i = i+1//Input integers you have.
    {
        printf("Input integer %d: ",i);
        scanf("%d", &x[i]);
        if(x[i] < 1)
        {
            printf("Error in integer %d.\n",i);
            exit(1);
        }        
    }

    printf("I will find the GCD of "); //I will check intergers you input.
    printf("integers: ( ");
    for(i=1; i <= max - 1; i = i+1)
    {
        printf("%d,",x[i]);
    }
    printf("%d )\n",x[max]);

    j = x[1] ;

    for( i = 1 ; i <= max ; i = i + 1 ) //I will find the GCD.
    {
        if(x[i] % j != 0)
        {
            i = 0 ;
            j = j - 1 ;
        }
    }

    printf("GCD( ");
    for(i=1; i <= max - 1; i = i+1)
    {
        printf("%d,",x[i]);
    }
    printf("%d ) ",x[max]);
    printf("= %d\n",j);
    
    printf("HAPPY SMILE (^_^)v\n");
    return 0;
}

今回もまた、2個の自然数だけではおもしろくないので、任意の個数の自然数を入力して、それらすべての最大公約数を求めるようなプログラムとした。そのせいで、急に難しくなり、色々と考えることとなった。結果的には、とても単純なコードとなったが、これに行き着くまでに割と時間がかかった。

練習問題 6.7(Newton法)

$${x}$$に関する一般の方程式$${f(x) = 0}$$の解は、導関数$${f'(x)}$$が解っている場合、次の操作を繰り返して近似的に求めることができる。

$$
x_{n+1}
= x_{n} - \dfrac{f(x_{n})}{f'(x_{n})}
$$

これを用いて、

$$
\begin{array}{lll}
f(x) = x^{2} - a \\
f(x) = x^{3} - a \\
f(x) = \sin x - a \\
\end{array}
$$

($${a}$$は定数)などの関数について$${f(x) =0}$$を解くプログラムを作成し、平方根や立方根などを求めてみよ。ループの終了については、$${|x_{n+1} - x_{n}|}$$の値が十分小さくなったとき(つまり上の操作を繰り返しても値が殆んど変わらなくなったとき)にほぼ収束したとみなして終了させるようにしてみよ。

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

int main()
{
    double x, x0 ;
    double delta, a, a0, a2 ;
    int n, n2 ;

    printf("I can calculate the n-th root.\n");
    printf("Input the number you want to know the n-th root: ");
    scanf("%lf", &a);
    printf("Input n(>0): ");
    scanf("%d", &n);

    a2 = a ;

    if(n <= 0)
    {
        printf("Error in n.\n");
        exit(1);
    }else if(n % 2 == 0// case: n = 2k
    {
        if(a < 0)
        {
            printf("Error in number you want to know the n-th root.\n");
            exit(1);
        }
    }else
    {
        a = fabs(a);
    }

    n2 = n ;
    while(n2 > 23)
    {
        n2 = n2 - 10 ;
    }

    printf("I calculate the %d", n);
    if( n2 == 1 || n2 == 21)
    {
        printf("st");
    }else if(n2 == 2 || n2 == 22)
    {
        printf("nd");
    }else if(n2 == 3 || n2 == 23)
    {
        printf("rd");
    }else
    {
        printf("th");
    }
    printf("-root of %f .\n", a2);

    x = a ;
    x0 = x ;
    delta = x ;

    while(fabs(delta) > 0.0000001)
    {
        x = x0 + (x0 / n) * ( a / pow(x0,n) - 1 ) ;
        delta = x - x0 ;
        x0 = x ;        
    }

    printf("the %d", n);
    if( n2 == 1 || n2 == 21)
    {
        printf("st");
    }else if(n2 == 2 || n2 == 22)
    {
        printf("nd");
    }else if(n2 == 3 || n2 == 23)
    {
        printf("rd");
    }else
    {
        printf("th");
    }
    printf("-root of %f = ", a2);

    if(a2 < 0 && n % 2 != 0)
    {
        x = x * (-1) ;
    }

    printf("%f\n", x);
    
    printf("HAPPY SMILE (^_^)v\n");
    return 0;
}

n乗根を求めるプログラムを作成した。n乗根の数値を求めること自体は、それほど難しくなかったが、printfで序数を正しく表示させるための条件分岐に少々悩んだ。数値計算とは異なる悩みではあるが、プログラミングの練習にはなったと思う。途中のNewton法のループ計算では、$${f(x) = x^{k} - a}$$を用いて、

$$
x_{n+1}
= x_{n} - \dfrac{f(x_{n})}{f'(x_{n})}
=x_{n} + \dfrac{x_{n}}{k} \left( \dfrac{a}{x_{n}^{k}} - 1 \right)
$$

とすることで、計算を行った。ただし、プログラムコードにおいては、$${n,n+1}$$を省略し、$${k \to n}$$としている。$${f(x) = \sin x - a}$$の方については、

$$
x_{n+1}
= x_{n} - \tan x_{n} + \dfrac{a}{\cos x_{n}}
$$

とすればよいだけなので、省略する。Newton法については、以下のページも参照した。

個数を数える

教科書を参考にして、入力した自然数$${n}$$以下の自然数で、3の倍数あるいは5の倍数である数の個数を数えるプログラムコードを書いた。

#include <stdio.h>

int main()
{
    int i, n, count ;
    count = 0 ;

    printf("Input n: ");
    scanf("%d", &n);

    for(i = 1 ; i <= n ; i = i + 1)
    {
        if( i % 3 == 0 || i % 5 == 0 )
        {
            count = count + 1 ;
            printf("%d-th element = %d\n", count, i);
        }
    }
    
    printf("\nTotal number = %d\n", count);

    printf("HAPPY SMILE (^_^)v\n");
    return 0;
}

若干、序数詞が気になったが、プログラミングの練習なので、ここでは深く考えないことにした。

素数判定

こちらも教科書を参考にして、入力した自然数$${n}$$が素数であるかどうかを判定するプログラムコードを書いた。

#include <stdio.h>

int main()
{
    int i, n, flag ;

    flag = 1 ;

    printf("Input n: ");
    scanf("%d", &n);

    for( i = 2 ; i < n ; i = i + 1 )
    {
        if( n % i == 0)
        {
            flag = 0 ;
        }
    }

    printf("\n%d is ", n);
    if( flag == 0 )
    {
        printf("not ");
    }
    printf("a prime number.\n");


    printf("HAPPY SMILE (^_^)v\n");
    return 0;
}

ここで、「flag」は、状態を表す変数として導入されており、これをフラグ変数という。このコードでは、$${n}$$は、「flag == 1」のときに素数であり、「flag == 0」のときに素数でない。

素数の個数を数える

範囲を指定して、その範囲内にある素数の個数を数えるプログラムコードを書いた。上で書いた「個数を数える」コードと「素数判定」コードを組み合わせることで、書くことができた。負の数の扱いや適切な範囲設定については、追加で考えることとなった。

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

int main()
{
    int n, min, min2, max ;
    int i, flag ;
    int count ;

    count = 0 ;

    printf("Input min of range: ");
    scanf("%d", &min);
    printf("Input max of range: ");
    scanf("%d", &max);
    
    if(min > max)
    {
        printf("Error in range.\n");
        exit(1);
    }
    if(min < 0)
    {
        min2 = 0 ;
    }else
    {
        min2 = min ;
    }

    for( n = min2 ; n <= max ; n = n + 1 )
    {
        flag = 1 ;

        if(n == 1 || n == 0)
        {
            flag = 0 ;
        }

        for(i = 2 ; i < n ; i = i + 1 )
        {
            if( n % i == 0 )
            {
                flag = 0 ;
                break;
            }
        }

        if( flag == 1 )
        {
            printf("%d ", n);
            count = count + 1 ;
        }
    }

    printf("\nThe number of prime numbers between %d and %d is %d .\n", min,max,count);
    
    printf("HAPPY SMILE (^_^)v\n");
    return 0;
}

コメント文

コード内で、「/*」と「*/」で囲まれた部分は、コメント文として処理され、コンパイル時に無視される。このコメントは、複数行に渡って記載することができる。また、「//」より右の部分もコメント文として処理されるが、このコメントは、単行のみ記載することができる。コメント文を記載することで、後で見直したときに、理解しやすくなることがある。

-----

動け!タイムライン

この記事が参加している募集

動物園か水族館にいきたいですね。