C言語

C の道具箱ー整数の処理

Project Euler の問題を解くためにプログラムした関数は、今後も使用できそうです。それらの関数を道具箱として、この記事でまとめておきます。

共通の説明

型は、int にしています。必要に応じて、unsigned int もしくは、unsinged long long int に変更して使います。

引数の確認をさぼっています。不正な入力に対しては正しく動作しません。

素数判定

与えられた自然数が、素数か素数でないかを判定する関数です。

int is_prime(int n)
 引数:n 自然数
 戻り値:素数なら 1、素数でなければ 0 を返す。

基本版

$\sqrt{n}$ まで調べます。$n$ が大きくなると、$n – 1$ まで調べたり、$n/2$ まで調べる場合と応答時間に大きな差がでます。

int is_prime(int n)
{
	int answer = 1;
	int i;

	if (n == 1) {
		answer = 0; /* 1 is not a prime number. */
	}
	for (i = 2; i * i <= n; ++i) {
		if (n % i == 0) {
			answer = 0;
			break;
		}
	}

	return answer;
}

初出は、Project Euler 問題5 です。

素数表版

何回も is_prime を呼び出す場合は、素数表を作っておくと計算量が少なくなる場合があります。エラトステネスの篩を使って素数表を作っておきます。素数を引く上限の値をマクロ定数 N として定義しておきます(1行目)。準備として先に generate_is_prime_table(N); を呼び出しておいてください。is_prime は、マクロ関数として配列の値を返しています(4行目)。

#define N 1000000
unsigned char is_prime_table[N+1];

#define is_prime(n) (is_prime_table[(n)])

void generate_is_prime_table(int n)
{
	int i, j;

	for (i = 2; i <= n; ++i) {
		is_prime_table[i] = 1;
	}

	for (i = 2; i * i <= n; ++i) {
		if (is_prime_table[i] == 1) {
			for (j = i + i; j <= n; j += i) {
				is_prime_table[j] = 0;
			}
		}
	}

	return;
}

初出は、Project Euler 問題10 です。

約数の個数を求める

与えられた自然数の約数の個数を返します。

int n_of_divisors(int n)
 引数:n 自然数
 戻り値:n の約数の個数を返す。

int n_of_divisors(int n)
{
	int answer = 0;
	int i;

	for (i = 1; i * i <= n; ++i) {
		if ((n % i) == 0) {
			if (i * i != n) {
				answer += 2;
			} else {
				++answer;
			}
		}
	}

	return answer;
}

初出は、Project Euler 問題12 です。

真の約数の和を求める

与えられた自然数の真の約数(与えられた自然数未満の約数)の和を返します。

int calc_sum_of_divisors(int n)
 引数:n 自然数
 戻り値:n の真の約数の和を返す。

int calc_sum_of_divisors(int n)
{
	int sum;
	int i;

	sum = 1; /* Add 1 (the first divisor) */
	for (i = 2; i * i <= n; ++i) {
		if ((n % i) == 0) {
			if (i * i != n) {
				sum += i;
				sum += n / i;
			} else {
				sum += i;
			}
		}
	}

	return sum;
}

初出は、Project Euler 問題21 です。

最大公約数を求める

ユークリッドの互除法を使って与えられた自然数 a と b のの最大公約数(GCD: Greatest Common Divisor)を返します。

int gcd(int a, int b)
 引数:a, b 自然数
 戻り値:a と b の最大公約数を返す。

int gcd(int a, int b)
{
	if (b == 0) {
		return a;
	} else {
		return gcd(b, a % b);
	}
}

初出は、Project Euler 問題5 です。

最後に

ここで紹介した関数は、効率も悪くなく、長く使える道具だと評価しています。このような道具を整備しておくのは、職人が道具を手入れしておく楽しみに通じると考えています。

みなさんも気に入った関数やマクロがあれば、道具箱として整理してはどうでしょうか。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA