電脳ミツバチのコンピュータ広報室

銀座の屋上菜園を耕しています。コンピュータ畑も耕します。

友愛数判定

スポンサーリンク

友愛数判定に挑戦してみる。
友愛数とは例えば220や284などで220の約数は1,2,4,5,10,11,20,22,44,55,110で合計すると284。同様に284の約数は1,2,4,71,142で合計で220である。
このように約数が互いを示す数のことを友愛数とよび、ピタゴラスが発見した。しかしながら2組目はピエール・ド・フェルマーが1636年に17296と18416を発見するまで見つかっておらず、数学者など数を愛する人たちに神秘的な数としてよく数学者の物語などに
登場する。最近では「博士の愛した数式」等に出てきてちょっとした話題になった。
現在数百種類見つかっている。因みに現在の2番目に小さい数は1184と1210で16歳のイタリア人学生が見つけた。

さて、ともかくまず約数を判定するコードが無ければならない。
掛ける数と掛けられる数をiとjとし、
二重ループでi*j==Nの時にiとjを足すことにする。

/*約数判定*/

#include<stdio.h>
#define N 18416
main()
{
	int i,j;/*jが掛けられるほう*/
	int divsum=0;
	for(i=1;i<N&&i*i<=N;i++)/*i*iがNを超えたらそれ以上は鏡なので無意味*/
	{
		for(j=N;j>=i;j--)
		{		
			if(N==i*j)
			{
				printf("%d,%d\n",i,j);
				if(i!=j)/* iとjが同じなら同じ数字を二回足してしまう*/
					{divsum=divsum+i+j;}
					else
					{divsum=divsum+i;}
			}
			
		}
	
	}
	divsum-=N;/*約数合計にNを含んでいるので消す*/
	printf("%d\n",divsum);
}

結果

Nを284
1,284
2,142
4,71
220

Nを220
1,220
2,110
4,55
5,44
10,22
11,20
284

Nを18416
1,18416
2,9208
4,4604
8,2302
16,1151
17296

何とかうまくいっている模様。
コツはi==jになってしまったらどちらか一方を足すことにすることと、
最後に必ず1*N=NというNが入ってしまうので引いてあげる。

さて、次に2つの約数を混ぜるにはどうしたらよいだろうか・・?
一番簡単なのは2つ並べて最後に2つが友愛数であるか判定する。
処理にオーバーヘッドがかかりすぎだが出来ないよりはずっといいのでとりあえずやってみる。

/*友愛数判定*/

#include<stdio.h>
#define N 18416
#define M 17296
main()
{
	int i,j;/*jが掛けられるほう*/
	int divsum=0,divsum2=0;
	for(i=1;i<N&&i*i<=N;i++)/*i*iがNを超えたらそれ以上は鏡なので無意味*/
	{
		for(j=N;j>=i;j--)
		{		
			if(N==i*j)
			{
				printf("%d,%d\n",i,j);
				if(i!=j)/* iとjが同じなら同じ数字を二回足してしまう*/
					{divsum=divsum+i+j;}
					else
					{divsum=divsum+i;}
			}
			
		}
	
	}
	divsum-=N;/*約数合計にNを含んでいるので消す*/
	printf("%d\n\n",divsum);
	

	for(i=1;i<M&&i*i<=M;i++)/*i*iがNを超えたらそれ以上は鏡なので無意味*/
	{
		for(j=M;j>=i;j--)
		{		
			if(M==i*j)
			{
				printf("%d,%d\n",i,j);
				if(i!=j)/* iとjが同じなら同じ数字を二回足してしまう*/
					{divsum2=divsum2+i+j;}
					else
					{divsum2=divsum2+i;}
			}
			
		}
	
	}
	divsum2-=M;/*約数合計にNを含んでいるので消す*/
	printf("%d\n",divsum2);

	if(divsum==M&&divsum2==N)
		puts("友愛数です。");
	else if(divsum==M||divsum==N)
		puts("準友愛数です。");
	else
		puts("友愛数ではない");
	
	
}
結果
1,18416
2,9208
4,4604
8,2302
16,1151
17296

1,17296
2,8648
4,4324
8,2162
16,1081
23,752
46,376
47,368
92,188
94,184
18416
友愛数です。

まあ、何とかうまく動いた。
次は1から順に調べていきたい・・何か新しい友愛数があるかも・・(99.9999.....%)無いが。w
とりあえずこの駄コードでCPU暖房機を生産する。

/*友愛数判定*/

#include<stdio.h>
#define LIMIT	1211
main()
{
	
	int i,j;
	int divsum=0,divsum2=0;
	int N,M;

	for(N=1;N<=LIMIT;N++)
	{
	for(M=1;M<=LIMIT;M++)
	{

	for(i=1;i<N&&i*i<=N;i++)
	{
		for(j=N;j>=i;j--)
		{		
			if(N==i*j)
			{
				if(i!=j)
					{divsum=divsum+i+j;}
					else
					{divsum=divsum+i;}
			}
			
		}
	
	}
	divsum-=N;
	

	for(i=1;i<M&&i*i<=M;i++)
	{
		for(j=M;j>=i;j--)
		{		
			if(M==i*j)
			{
				if(i!=j)
					{divsum2=divsum2+i+j;}
					else
					{divsum2=divsum2+i;}
			}
		}
	
	}
	divsum2-=M;

	if((divsum==M&&divsum2==N)&&N!=M)
		printf("%dと%dは友愛数です。",N,M);
		
	divsum=0;
	divsum2=0;/*初期化*/
	}
	}
	

	
}

	
	
	


結果
220と284は友愛数です。284と220は友愛数です。1184と1210は友愛数です。1210と1184は
友愛数です。 -- Press any key to exit (Input "c" to continue) --

入れ子が多すぎて他人の読む限界をおそらく超えてしまったコードになったが思考過程を辿っていけば当たり前に書ける駄コードなので解説は抜いた。
人前に出す必要があるなら関数にして分かりやすく記述する必要がある。
自分用コードなので処理の手間を少しでも短くするほうを選んだ。
まぁ1211までの中に新たな友愛数は無いことは分かった。