友愛数と婚約数
友愛数とは異なる2つの自然数の組で、自分自身を除いた約数の和が互いに他方と等しくなるような数のことです。
220の約数は、1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110, 220で、220を除く約数を全部足すと284になります。一方、284の約数は、1, 2, 4, 71, 142, 284で、284以外の約数の和は220です。(220, 284)は友愛数です。そして最小の友愛数の組です。
また異なる2つの自然数の組で、1と自分自身を除いた約数の和が、互いに他方と等しくなるような数を婚約数といいます。友愛数の場合、偶数同士または奇数同士になりますが、婚約数は片方が偶数で他方が奇数になります。
最小の婚約数の組は (48, 75) です。48の約数は 1, 2, 3, 4, 6, 8, 12, 16, 24, 48で1と48を除く約数の和は 75です。75の約数は 1, 3, 5, 15, 25, 75で1と75を除く約数の和は48です。このことから (48, 75)は婚約数であることがわかります。
昔の数学の世界においては、偶数が女性を奇数が男性を表すものと考えられていました。友愛数は同性同士の関係、婚約数は異性同士の関係です。また婚約数はその数だけでなく1も除外されているので、結婚の一歩前であるとしてこのような名前がつけられました。
もし偶数と奇数の友愛数が存在するのであれば、これは異性同士の友愛=結婚となるのですが、実際に一方が偶数で他方が奇数である友愛数は発見されていません。また結婚数は存在しないという証明もされていないので探してみると面白いかもしれません。
では友愛数婚約数を探してみましょう。
まず友愛数から。友愛数は英語では amicable numbers です。
まず引数で渡された値の約数を調べます。GetDivisorメソッドは
を参照してください。
約数をすべて足してそこから引数を引きます。これでその数以外の約数をすべて足した値を得ることができます。次に得られた数の約数をしらべて総和を求めてそこからその数を引きます。このとき引数と一致すれば友愛数を発見できたことになります。その場合はペアになる整数を返します。
上記の操作をして引数と同じ値にならなかった場合、引数は友愛数の組を構成する自然数ではないことになります。この場合は-1を返します。
引数以外の約数をすべて足した値が引数と同じ場合は除外します。この場合は引数は完全数になっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
int GetAmicable(int i) { // 1は約数がひとつしかないので除外する if(i <= 1) return -1; List<long> vs = GetDivisor(i); int ii = (int)vs.Sum() - i; List<long> vs1 = GetDivisor(ii); if(vs1.Sum() - ii == i && i != ii) return ii; else return -1; } private void button1_Click(object sender, EventArgs e) { List<string> list = new List<string>(); for(int i = 2; i < 100000; i++) { int ret = GetAmicable(i); if(ret != -1 && ret > i) { // 前者よりも後者が小さい値の場合は取得しない list.Add(String.Format("{0:#,0} と {1:#,0}", i, ret)); } } textBox1.Text = String.Join("\r\n", list.ToArray()); } |
最初はループを1,000回で実験してみましたが、友愛数のペアはひとつ(220 と 284)しか見つかりませんでした。ループが10,000回程度であればすぐ終わりますが、100,000回となると相当待たされます。
100,000までの友愛数の組は以下のとおりです。
出力結果
220 と 284
1,184 と 1,210
2,620 と 2,924
5,020 と 5,564
6,232 と 6,368
10,744 と 10,856
12,285 と 14,595
17,296 と 18,416
63,020 と 76,084
66,928 と 66,992
67,095 と 71,145
69,615 と 87,633
79,750 と 88,730
では次に婚約数について調べてみます。婚約数は英語ではbetrothed numbersです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
int GetBetrothed(int i) { // 1,2, 3は1とその数以外の約数が存在しないので除外する if(i <= 3) return -1; List<long> vs = GetDivisor(i); int ii = (int)vs.Sum() - i -1; // 1とその数以外の約数が存在しない場合は ii == 0 になる。 // この場合は -1 を返す if(ii == 0) return -1; List<long> vs1 = GetDivisor(ii); if(vs1.Sum() - ii - 1 == i && i != ii) return ii; else return -1; } private void button2_Click(object sender, EventArgs e) { List<string> list = new List<string>(); for(int i = 2; i < 100000; i++) { int ret = GetBetrothed(i); if(ret != -1 && ret > i) { list.Add(String.Format("{0:#,0} と {1:#,0}", i, ret)); } } textBox1.Text = String.Join("\r\n", list.ToArray()); } |
100,000までの婚約数の組は以下のとおりです。
出力結果
48 と 75
140 と 195
1,050 と 1,925
1,575 と 1,648
2,024 と 2,295
5,775 と 6,128
8,892 と 16,587
9,504 と 20,735
62,744 と 75,495
友愛数の補足
友愛数を生成する法則としてサービト・イブン=クッラの法則とオイラーの法則があります。
サービト・イブン=クッラの法則は
p = 3 × 2^(n-1) – 1
q = 3 × 2^n – 1
r = 9 × 2^(2n-1) – 1
nは2以上の整数、p,q,rが素数であるとすると、2^n × p × q と 2^n × r は友愛数の対となる。
オイラーの法則は、サービト・イブン=クッラの法則を一般化したもので、mはm<nを満たす正の整数としたときに2^n × p × q と 2^n × r は友愛数の対となるというものです。
p = (2^(n-m) + 1) × 2^m – 1
q = (2^(n-m) + 1) × 2^n – 1
r = (2^(n-m) + 1)^2 × 2^(m+n) – 1
ただすべての友愛数の組に対して成立するわけではないとのことです。これも実験してみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
bool Qurra(int n, out long a, out long b) { a = -1; b = -1; if(n <= 1) { return false; } long p = 3 * (long)Math.Pow(2, n - 1) - 1; long q = 3 * (long)Math.Pow(2, n) - 1; long r = 9 * (long)Math.Pow(2, 2 * n - 1) - 1; if(IsPrime(p) && IsPrime(q) && IsPrime(r)) { a = (long)Math.Pow(2, n) * p * q; b = (long)Math.Pow(2, n) * r; return true; } else return false; } private void button3_Click(object sender, EventArgs e) { List<string> list = new List<string>(); int count = 500; for(int i = 1; i < count; i++) { long a, b; if(Qurra(i, out a, out b)) { list.Add(String.Format("{0:#,0} と {1:#,0}", a, b)); } } textBox1.Text = String.Join("\r\n", list.ToArray()); } |
出力結果
220 と 284
17,296 と 18,416
9,363,584 と 9,437,056
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
bool Euler(int m, int n, out long a, out long b) { a = -1; b = -1; if(n <= m) { return false; } long p = (long)(Math.Pow(2, n - m) + 1) * (long)Math.Pow(2, m) - 1; long q = (long)(Math.Pow(2, n - m) + 1) * (long)Math.Pow(2, n) - 1; long r = (long)(Math.Pow(2, n - m) + 1) * (long)(Math.Pow(2, n - m) + 1) * (long)Math.Pow(2, m + n) - 1; if(IsPrime(p) && IsPrime(q) && IsPrime(r)) { a = (long)Math.Pow(2, n) * p * q; b = (long)Math.Pow(2, n) * r; return true; } else return false; } private void button4_Click(object sender, EventArgs e) { List<string> list = new List<string>(); int count = 30; for(int i= 1; i < count; i++) { for(int j = i+1; j < count; j++) { long a, b; if(Euler(i, j, out a, out b)) { list.Add(String.Format("{0:#,0} と {1:#,0}", a, b)); } } } textBox1.Text = String.Join("\r\n", list.ToArray()); } |
出力結果
220 と 284
2,172,649,216 と 2,181,168,896
17,296 と 18,416
9,363,584 と 9,437,056
2,172,649,216 と 2,181,168,896を新しく見つけることができました。ループ回数を増やしても処理に時間がかかるだけで4つしか取得できません。 (1184, 1210), (2620, 2924), (5020, 5564), (6232, 6368), (10744, 10856), (12285, 14595)などを取得することはできませんでした。