Project Euler

Project Euler 問題20(階乗の桁の和)を解いてみる

Euler_020

Project Euler で紹介されている問題20を解いてみました。階乗は数が大きくなります。このため、大きな整数を使える言語を利用します。扱う数が異なりますが、問題16と同じ方針となります。

Project Euler 問題20(階乗の桁の和)

n! は、n×(n1)××3×2×1 を表す。

例えば、10!=10×9××3×2×13628800 となる。10! の各桁の和は、3+6+2+8+8+0+0=27 となる。

100! の各桁の和を求めよ

解答例

階乗は非常に速く大きくなります。階乗の近似として、次のスターリングの公式が知られています。

n!2πn(ne)n

この近似式の両辺に対して log10 を取ると以下になります。

log10n!12log102πn+n(log10nlog10e)

n=100 を代入すると、右辺の値は、159.792 と計算できます。100! は、160 桁と近似できるわけです。実際には158 桁となります。

158 桁の数字を扱うため、整数の長さに制約がない Python で実装してみます。math モジュールにある階乗を求める関数 factorial を使います。プログラムは以下です。

"""Project Euler Problem025"""
import math

answer = 0
for n in str(math.factorial(100)):
    answer += int(n)
print("Problem020: " + str(answer))

GMP ライブラリを使って、C言語でも記述しました。GMP にも階乗を求める関数 mpz_fac_ui があるため、これを使います。また、関数 mpz_fdiv_q_ui(n, n, 10) は、n=n/10 を計算して、10 で割った余りを関数の戻り値として返すため、すっきりとプログラムを書くことができました。

#include <stdio.h>
#include <gmp.h>

int main(void)
{
	int sum;
	mpz_t n;

	mpz_init(n);
	mpz_fac_ui(n, 100); /* n = 100! */

	sum = 0;
	while (mpz_sgn(n) != 0) {
		sum += mpz_fdiv_q_ui(n, n, 10);
	}

	printf("Problem020: %d\n", sum);
	mpz_clear(n);

	return 0;
}

GMP ライブラリを使っているため、コンパイル時(リンク時)には、「-lgmp」オプションが必要となります。また多くのオンライン実行環境では、コンパイルできません。

最後に

階乗は、非常に速く大きくなるため「!」という記号で記す、と聞いたことがありますが、確かに速く大きくなります。プログラムは、大きな整数を扱うという難しさはありますが、計算の仕組みは分かりやすい問題だと考えています。

引き続き、Project Euler の問題を紹介していきます。

COMMENT

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

CAPTCHA