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

ラングレーの問題はすべて解決したのか?

$
0
0
久しぶりにラングレーの問題について書いてみる。

ラングレーの問題、フランクリンの凧、整角四角形問題、などなど、いろいろな名前で呼ばれている。

簡単に説明すると、

ある凸四角形があり、
それぞれの頂点を、反時計回りに左上からA、B、C、Dとし、
AC、DC、の対角線を結んだ図形において、
底辺BCとした下方に出来る4角、
∠ABD=α˚
∠DBC=β˚
∠ACB=γ˚
∠ACD=δ˚
とし、これらの値が度数法で整数となる値が与えられ、
∠ADB=θ˚
を求める問題。

α=20、β=60、γ=50、δ=30のものを、ラングレーの問題と呼んだりする。

凸四角形と対角線で凧に見えることから、フランクリンの凧、

与えられた角および、求める角がすべて、整数の角になることから、整角四角形問題、

などと言う。


これらの問題は、初等幾何学、代数学の範疇で解かなければダメという縛りが存在する。

簡単に言えば、解析学的に解いてはダメということです。


前回の記事は、



こんな感じ。


今回は、前回の記事で、整角整数問題の問題数は、1002733個ということを、プログラムで数え上げたと書いた。

その辺について、サンプルを交えて詳しく書いてみようかと思う。


まず、解くのに解析学は使えないが、何個あるのかを数えるのには使っても良いだろうと考える。

何を使うかといえば、逆三角関数である。

なお、プログラミングにα、β、γ、δ、θは変数として使えないので、それぞれ、a、b、c、d、xとする。


例えば、Javascriptならば、

var deg=180.0/Math.PI;
var rad=Math.PI/180.0;
var e = Math.tan(c*rad)/(Math.tan((a+b)*rad)+Math.tan(c*rad));
var f = Math.tan(b*rad)/(Math.tan((d+c)*rad)+Math.tan(b*rad));
var g = e*Math.tan((a+b)*rad);
var h = f*Math.tan((d+c)*rad);
var x = b-Math.atan2(h-g,1-e-f)*deg;


例えば、Excelならば、

A1セルにa、B1セルにb、C1セルにc、D1セルにdの値が入っていたとして、

E1セルに、
=TAN(RADIANS(C1))/(TAN(RADIANS(A1+B1))+TAN(RADIANS(C1)))

F1セルに、
=TAN(RADIANS(B1))/(TAN(RADIANS(C1+D1))+TAN(RADIANS(B1)))

G1セルに、
=E1*TAN(RADIANS(A1+B1))

H1セルに、
=F1*TAN(RADIANS(C1+D1))

I1セルにxの値を求めるため、
=B1-DEGREES(ATAN2(1-E1-F1,H1-G1))


どちらにしても、xをatan2、数学で言うところのarctan、逆正接関数(アークタンジェント)を使って求めている。

つまり、逆三角関数を使えば、α、β、γ、δの取り得る値であれば、θを求めることが出来るということでもある。

※因みに、関数としてatanではなく、atan2を使ったのは、分母が0になる可能性があるからです。


とは書いたものの、プログラミング言語で計算するわけであるから、三角関数や逆三角関数といった小数を扱う関数において、誤差というものを考えなければならない。

小数点以下に0が何個続けば、整数とみなすのか。
はたまた、小数点以下に9が何個続けば、繰り上げて整数とみなすのか。

ということを考えなければならないだろう。


とりあえず、この問題は一旦置いておいて、いったいどれくらいの母数があるのかを探ってみる。

for (a=1; a<178; a++) {
    for (b=1; a+b<179; b++) {
        for (c=1; a+b+c<180; c++) {
            for (d=1; b+c+d<180; d++) {
                /* ここに処理を書く */
            }
        }
    }
}

もしくは、

for (a=1; a<178; a++) for (b=1; a+b<179; b++) for (c=1; a+b+c<180; c++) for (d=1; b+c+d<180; d++) {
    /* ここに処理を書く */
}

といったネスト(入れ子)になる。

因みに、このループの回数を数えると、83653681回となります。

a、b、c、dは整数を入れても、かならずxが整数となるかは解らないので、このループ回数が、整角四角形問題の総数ではないことは、明らかである。


そこで、以下のようなJavascriptのプログラムを考えてみた。

簡単に説明すると、

arctanで求めた小数のままのθ(プログラムではx)の値と、
整数化したθ(プログラムではy)の値との差の絶対値を、
log10を取ったもので分布してカウントする。
α=δ、すなわち円に内接する、
α≠δ、すなわち円に内接しない、
も同様に別途カウントする。

var a, b, c, d, e, f, g, h, x, y;
var deg=180.0/Math.PI;
var rad=Math.PI/180.0;
var count0=new Array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
var count1=new Array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
var count2=new Array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);

for (a=1; a<178; a++) for (b=1; a+b<179; b++) for (c=1; a+b+c<180; c++) for (d=1; b+c+d<180; d++) {
    e = Math.tan(c*rad)/(Math.tan((a+b)*rad)+Math.tan(c*rad));
    f = Math.tan(b*rad)/(Math.tan((d+c)*rad)+Math.tan(b*rad));
    g = e*Math.tan((a+b)*rad);h = f*Math.tan((d+c)*rad);
    x = b-Math.atan2(h-g,1-e-f)*deg;
    switch ( parseInt(x*10)%10 ) {
    case 0:
        y = parseInt(parseInt(x*10)/10);
        break;
    case 9:
        y = parseInt(parseInt(x*10+1)/10);
        break;
    default:
        y = -1;
        break;
    }
    if ( y > 0 ) {
        if ( Math.abs(x-y) > 0.0 ) {
            count0[-parseInt(Math.log10(Math.abs(x-y)))]++;
            if ( a == d ) {
                count1[-parseInt(Math.log10(Math.abs(x-y)))]++;
            } else {
                count2[-parseInt(Math.log10(Math.abs(x-y)))]++;
            }
        } else {
            count0[count0.length-1]++;
            if ( a == d ) {
                count1[-parseInt(Math.log10(Math.abs(x-y)))]++;
            } else {
                count2[-parseInt(Math.log10(Math.abs(x-y)))]++;
            }
        }
    } else {
        count0[0]++;
        if ( a == d ) {
            count1[-parseInt(Math.log10(Math.abs(x-y)))]++;
        } else {
            count2[-parseInt(Math.log10(Math.abs(x-y)))]++;
        }
    }
}
var str = '<table><tr align="center"><td>10^-n</td><td style="width: 15ch;">全事象</td><td style="width: 15ch;">円に内接する</td><td style="width: 15ch;">円に内接しない</td></tr>';
for (var i=0; i<count0.length; i++) str += '<tr align="right"><td>'+i+'</td><td>'+count0[i]+'</td><td>'+count1[i]+'</td><td>'+count2[i]+'</td></tr>';
str += '</table>';
document.getElementById('inner').innerHTML = str;


出力結果は、このようになった。

10^-n
全事象円に内接する円に内接しない
066750978066750978
114411215014411215
2135332801353328
31234710123471
411412011412
54960496
648048
7000
8000
9000
103143086
1167466594152
1275134719253209
1343313940766525474
1421308319728015803
1557565604152
16000
17000
18000
1926856125055318008

まず、円に内接するケースに着目すると、円に内接するすなわち、α=δより、円周角よりθ=γとなり、整角四角形問題となることは明白である。

故に、円に内接するの分布域は、すべて誤差の範疇と言える。

円に内接しないケースも同様な分布域、もしくは多少精度の悪い分布域を示す可能性はあったが、10^-nの7~9に明らかなフタコブラクダの谷間が出来ており、同様に8以降は誤差の範疇と考えるに至る。

これより、

整角四角形問題の総数は、
314+6746+75134+433139+213083+5756+268561=1002733

円に内接するものは、
308+6594+71925+407665+197280+5604+250553=939929

円に内接しないものは、
6+152+3209+25474+15803+152+18008=62804

という個数が求まったのである。

同様のことを、C言語でやってみたが、結果は同じようにフタコブラクダの谷間ができ、誤差と捉えた部分の分布は違っても、上記の合計は全て等しかった。

ただ、プログラミング言語においても、フタコブラクダの谷間が0となるかは、関数や変数の精度次第だろう。


さて、プログラミングはここまでとし、数学にもどる。

ラングレーの問題、フランクリンの凧、整角四角形問題、

いずれにしても、初等的な逆三角関数なら使ったとしても、解析的な逆三角関数を使わずに解くということが、この問題の醍醐味である。

どれだけ単純で簡単な方法で導くかというところの勝負でもある。

ラングレーの問題にトドメをさす!―4点の作る小宇宙完全ガイド/現代数学社
¥価格不明
Amazon.co.jp

現代数学 2016年 02 月号 [雑誌]/現代数学社
¥価格不明
Amazon.co.jp

本当に1002733個すべてを分類して、すべてにおいて初等幾何学、代数学の範疇で答えを導き出せたのだろうか。

これらの書籍を読めば解るのだろうか。

まぁ、1002733という総数とラングレーの問題等とを紐付けしてネットで検索しても、みつかるのは、こののブログくらいなものだろう。


さて、Owndにでもプログラムを書こうかな。


ではでは

Viewing all articles
Browse latest Browse all 5376

Trending Articles