数学をやっている方のためのプログラミング講座


例1 階乗

自然数 n (≧0)の階乗を計算することを考えます。 n の階乗(n!)は、以下のように帰納的に定義されます。 (ここで「*」はかけ算を表します(プログラミング言語Cでの記法))

この定義は、階乗を計算するための手順と考えることもできます。 計算の手順を表すために、次の記法を使うことにします。

この記法を使うと、n の階乗 f(n) は、以下のように定義することができます。
f = function(n; if(n = 0; 1; n * f(n - 1)))
これは
f(n) = if(n = 0; 1; n * f(n - 1))
と書いてもよいことにします。

この手順をプログラミング言語Cで書いてみます。

Cでの記述例:

	int f(int n)
	{
		if ( n == 0 ) {
			return 1;
		} else {
			return n * f(n - 1);
		}
	}

例2 階乗

n の階乗を計算するために、次のような自然数の列 k[0], k[1], k[2], … , k[n] = n! を考えます。 各 i に対して k[i] は i の階乗となるようにします。 階乗の定義より、

計算の手順を表すために、次の記法を使います。

この記法を使うと、n の階乗 f(n) は、以下のように定義することができます。 上の手順を書き直すと、

これより (i[μ], k[μ]) という組から (i[μ+1], k[μ+1]) いう組を得る関数 function(i, k; i + 1, i * k) を得ることができます。 したがって f(n) は以下のようになります。
f(n) = while(function(i, k; i <= n); 1, 1; function(i, k; i + 1, i * k))(1)
(「i <= n」は i が n に等しいか i が n より小さいことを表します) この手順をプログラミング言語Cで書いてみます。

Cでの記述例1:

	int f(int n)
	{
		int i;
		int k;
		i = 1;
		k = 1;
		while ( i <= n ) {
			k *= i;
			i++;
		}
		return k;
	}

Cでの記述例2:

	int f(int n)
	{
		int i;
		int k;
		k = 1;
		for ( i = 1; i <= n; i++ ) {
			k *= i;
		}
		return k;
	}

例3 最大公約数

自然数 m、n (≧0)の最大公約数 g(m, n) を計算することを考えます。 n > 0 のときは、g(m, n) = g(n, m % n) となります。 (「m % n」は m を n で割った余りを表します) この性質を使うと、g(m, n) を計算する手順を、 以下のように記述することができます。 (互除法)

今までの記法を使って

g(m, n) = if(n = 0; m; g(n, m % n))
または
g(m, n) = while(function(i, j; j > 0); m, n; function(i, j; j, i % j))(0)
と書くことができます。

この手順をプログラミング言語Cで書いてみます。

Cでの記述例1:

	int g(int m, int n)
	{
		if ( n == 0 ) {
			return m;
		} else {
			return g(n, m % n);
		}
	}

Cでの記述例2:

	int g(int m, int n)
	{
		int i;
		int j;
		int k;
		i = m;
		j = n;
		while ( j > 0 ) {
			k = i;
			i = j;
			j = k % j;
		}
		return i;
	}

Cでの記述例3:

	int g(int m, int n)
	{
		int i;
		int j;
		int k;
		for ( i = m, j = n; j > 0; k = i, i = j, j = k % j ) {
		}
		return i;
	}

例4 素数1

自然数 n (≧2)が素数かどうかを調べることを考えます。 n が素数であるということを p(n) と書くとすると、p(n) は 「n が自然数 m (≧1)で割り切れるならば、m = 1 または m = n である」 と定義することができます。 n が自然数 m で割り切れるならば、1 ≦ m ≦ n なので、これは、 「1 < m < n ならば n は m で割り切れない」 ということもできます。 これは以下のように記述することができます。 値が真理値(T または F)となる列 q[2], q[3], … , q[n - 1] を使って、

今までの記法を使って

p(n) = while(function(i, q; q && i * i <= n); 2, T; function(i, q; i + 1, q && (n % i != 0)))(1)
と書くことができます。

この手順をプログラミング言語Cで書いてみます。

Cでの記述例1:

	bool p(int n)
	{
		int i;
		bool q;
		i = 2;
		q = true;
		while ( q && i * i <= n ) {
			q = (q && (n % i != 0));
			i++;
		}
		return q;
	}

Cでの記述例2:

	bool p(int n)
	{
		int i;
		bool q;
		q = true;
		for ( i = 2; q && i * i <= n; i++ ) {
			q = (q && (n % i != 0));
		}
		return q;
	}

例5 素数2

前の例と同様に 自然数 n (≧2)が素数かどうかを調べることを考えます。 n が自然数 m (≧2)で割り切れるならば、n は m を割り切るある素数 p で割り切れるので、
p(n) = while(function(i, q; q && i * i <= n); 2, T; function(i, q; i + 1, q && (!p(i) || (n % i != 0))))(1)
と書くことができます。 (|| は論理和、!は否定を表します。)

Cでの記述例:

	bool p(int n)
	{
		int i;
		bool q;
		q = true;
		for ( i = 2; q && i * i <= n; i++ ) {
			q = (q && (!p(i) || (n % i != 0)));
		}
		return q;
	}
この関数を使って、2 から n までの素数を探すことを考えます。 s[i] (i = 2, … , n) を i が素数のとき true、i が素数ではないとき false であるものとします。

Cでの記述例:

	bool s[1000];

	bool p(int n)
	{
		int i;
		bool q;
		q = true;
		for ( i = 2; q && i * i <= n; i++ ) {
			q = (q && (!s[i] || (n % i != 0)));
		}
		return q;
	}

	void find_prime(int n)
	{
		int i;
		for ( i = 2; i <= n; i++ ) {
			s[i] = p(i);
		}
	}