Quantcast
Channel: 円周率近似値の日に生まれて理系じゃないわけないだろ! - knifeのblog
Viewing all articles
Browse latest Browse all 5376

666

$
0
0

午後のひとときに、数学の問題なのか、プログラミングの問題なのかにチャレンジしてみる。

問題
nC2が6、66、666、…となるような、nを求めよ。


シンキングタ~イム


プログラミングするにも、数学的な考証は必要ですね。

nCrとは何でしょう。

読みは、
コンビネーションと呼びます。

意味は、
異なるn個からr個を選ぶときの、組み合わせの数。

数式は、
nCr=n!/((n-r)!・r!)
ですが、
分子はnから下がっていったr個の積、
分母は1から上がっていったr個の積、
と考えると、今回のケースは
nC2=n(n-1)/2
で良い。

では、6、66、666、…をどの様に数式にするかというと、
これはレピュニット数
R(m)=(10m-1)/9
を使って、
6R(m)=6(10m-1)/9=2(10m-1)/3
と表せる。

というわけで、
n(n-1)/2=2(10m-1)/3
3n(n-1)=4(10m-1)
といった数式を導ける。

左辺は3の倍数であることは係数3から解り、
もっといえば、連続する2整数の積なので、n(n-1)は2の倍数となり、
都合6の倍数だということが解ります。

右辺は4の倍数であることは係数4から解ります。

左辺は6の倍数となっているが、
n(n-1)は4の倍数でなければなりません。

もし、nを基準に手計算やプログラミングするならば、
nかn-1が4の倍数となるようにループさせることになります。

手計算でやってみましょう。

n=4のとき、
3×4×3=4(10m-1)
9=10m-1
9+1=10m
m=1
故に、
4C2=6

n-1=4のとき、
3×5×4=4(10m-1)
15=10m-1
16=10m
不適

n=8のとき、
3×8×7=4(10m-1)
42=10m-1
43=10m
不適

n-1=8のとき、
3×9×8=4(10m-1)
54=10m-1
55=10m
不適

n=12のとき、
3×12×11=4(10m-1)
99=10m-1
100=10m
m=2
故に、
12C2=66

n-1=12のとき、
3×13×12=4(10m-1)
117=10m-1
118=10m
不適



このまま続けてもいいですが、
答えがあるかも解らないものを手計算でやるのは無理があります。

もっといえば、左辺のnをインクリメントさせて解いて行くのがスマートなのだろうか。

私は、右辺のmをインクリメントさせて解いて行くのがスマートだと考えます。
左辺のnをインクリメントさせても、なかなか大きくなりませんが、右辺のmをインクリメントさせると、簡単に大きくなりますよね。
つまり、無駄が少ないのは右辺の方ですね。

右辺のmを基準に、手計算でやってみましょう。

m=1のとき、
3n(n-1)=4(101-1)=4・9
n(n-1)=4・3
n=4
故に、
4C2=6

m=2のとき、
3n(n-1)=4(102-1)=4・99=4・9・11
n(n-1)=12・11
n=12
故に、
12C2=66

m=3のとき、
3n(n-1)=4(103-1)=4・999=4・9・111=4・9・3・37
n(n-1)=37・36
n=37
故に、
37C2=666

m=4のとき、
3n(n-1)=4(104-1)=4・9999=4・9・1111=4・9・11・101
不適

m=5のとき、
3n(n-1)=4(105-1)=4・99999=4・9・11111=4・9・41・271
不適



明らかに、m基準で考えたほうが速いことが解ります。


さて、ここからはプログラミング的な考察です。

素因数分解は、プログラミング的には時間がかかりすぎます。
この時間がかかることを利用して、暗号鍵とかに使われているくらいです。

というわけで、プログラミングで素因数分解のコード自体はそれほど難しくないのですが、時間がかかりすぎるということで、今回はそれを素因数分解はやりたくありません。

さて、みなさんはどうしますか?

私が考えた方法は、
3n(n-1)=4(10m-1)
の式をもう少し変化させます。
10m-1=9R(m)なので、
3n(n-1)=4・9R(m)
n(n-1)=12R(m)

ここで、左辺は差が1の整数の積ならば、右辺に√を取って、
x=12R(m)
xは、12R(m)が平方数で無い限り、無理数ですね。
というわけで、
n=ceil(x)
n-1=floor(x)
というように考えて、
ceil(x)*floor(x)=12R(m)
となれば、そのm、n=ceil(x)、において成り立つということです。

レピュニット数は簡単に大きくなっていくので、素因数分解はどんどんと難しくなっていく。
それを考えたら、√を取るくらいは楽な計算だと言えます。

例えば、多倍長電卓LMにて、有効桁数を1000桁よりもちょっと大きくして、

for (m=1; m<1001; m++) {
    r = 12*(10^m-1)/9;
    x = r^(1/2);
    if ( ceil(x)*floor(x) == r ) printf("m=%d, n=%d\n", m, ceil(x));
    else printf("m=%d is not found.\n", m);
}


で、試したところ、ものの数秒でm=1000まで調べあげましたが、
m=1, n=4
m=2, n=12
m=3, n=37
以外に、解をみつけられませんでした。

m=10000まで、調べさせているが、有効桁数を1万桁ちょいにしたので、かなり時間が掛かっていて、既に12時間くらい経っているが、まだ5000桁程度までしか達していない。

例えば、C言語でプログラムを書いたならば、

 

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()

{
    unsigned int m, n;
    unsigned long long r;

    r=1;
    for (m=1; m<20; m++) {
        n = sqrtl(12*r)+1;
        if ( n*(n-1) == 12*r ) {
            printf("m=%u, n=%u\n", m, n);
        }
        r *= 10;
        r += 1;
    }
    return EXIT_SUCCESS;
}


もしくは、do-whileで回して、終了条件をオーバーフローにするとか、
 

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
    unsigned int m, n;
    unsigned long long r, b;

    r=1;
    m=1;
    do {
        n = sqrtl(12*r)+1;
        if ( n*(n-1) == 12*r ) {
            printf("m=%d, n=%d\n", m, n);
        }
        b = r;
        r *= 10;
        r += 1;
        m++;
    } while ( b < r );
    printf("m=%d\n",m-1);
    return EXIT_SUCCESS;
}

 

こんな感じだろうか。

これって、上記3つ以外に解があるのだろうか。

もしかして、未解決問題なのかなぁ。


ではでは

 


Viewing all articles
Browse latest Browse all 5376

Trending Articles