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

数学とプログラミングの関係

$
0
0

今回は、ちょっと趣向を凝らして、図形問題から、数学とプログラミングについて書いて行こうかと思う。



上図のような、
点Oを中心とする半円において、
∠ABF=∠FBC、∠BAD=∠DAC
線分DE=2、線分EF=1のとき、
線分BD=xを求めよ。


シンキングタ~イム


この問題、自分は数学よりもプログラミングで解いてしまったので、数学コミュニティの方々の解法を見て、随分と自分は数学を忘れているなぁと思ってしまいました。


というわけで、まずは代数幾何として解いてみます。

∠ABF=∠FBC
これらを円周角としてみると、
弧AF、弧FCも等しい。
そこで、補助線として、線分AF、線分FCを引く。
当然、線分AF=線分FCである。

線分AF=線分FC=y
とする。

ここで、完全に頭から抜け落ちていた定理を使う。
方べきの定理。
y2=x+2+1=x+3 …(1)

とりあえず、yとxの関係式が1つ出来ました。
もう一つあれば、連立方程式で求まりますね。

今度は、
三角形ABE、∠BAD=∠DAEに着目する。
∠BAEの2等分線なので、
AB:AE=x:2 …(2)

続いて、三角形ABEと三角形CFEに着目する。
∠BACと∠BFCは同じ円周を持つ角、つまり同じ円周角なので角度が等しい。
また、∠AEBと∠FECも等しい。
よって、三角形ABEと三角形CFEは相似である。
相似比を使うと、
AB:AE=y:1 …(3)

(2)=(3)なので、
x:2=y:1
外項の積と内項の積は等しいので、
2y=x …(4)

(4)を(1)に代入して、
y2=2y+3
y2-2y-3=0
y=(2±4)/2=1±2
y>0なので、
y=3
x=6

答え 6


さて、ここからが本題。

自分は上記の解法を思い浮かばなかったわけですが、
Javascript+HTML5で作図出来ました。

どうやったかというと、数学でいうところの解析学で近似値を求めました。
簡単に言うと、二分法を使いました。

とりあえず、いくつかの変数を準備しましょう。

// x-y座標
var Ox, Oy, Ax, Ay, Bx, By, Cx, Cy, Dx, Dy, Ex, Ey, Fx, Fy;
// 線分の長さ
var BA, BD, BE, BD, DE, EF;
// 角
var AOC, ABC, FBC, FOC, BAD;
// 頂点から垂線の足の高さ
var Dh, Eh;
// 二分法の最大値と最小値
var AOCMax, AOCMin;

// 点O、点B、点Cの座標を設定
Ox=0;
Oy=0;
Bx=-350;
Cx=+350;
Cy=By=Oy;



∠AOCについて、二分法を行います。

 

// 最大値と最小値を設定
AOCMax = 180;
AOCMin = 0;

// 64ビットを想定して、64回まわす。
for (var i=0; i<64; i++) {
    // 角を計算
    AOC=(AOCMax+AOCMin)/2;
    ABC=AOC/2;
    FBC=ABC/2;
    FOC=ABC;
    BAD=ABC-135;

    // 座標を計算
    Ax=Ox+r*Math.cos(AOC*Math.PI/180.0);
    Ay=Oy-r*Math.sin(AOC*Math.PI/180.0);
    Fx=Ox+r*Math.cos(FOC*Math.PI/180.0);
    Fy=Oy-r*Math.sin(FOC*Math.PI/180.0);
    BA=Math.sqrt((Bx-Ax)*(Bx-Ax)+(By-Ay)*(By-Ay));
    Dh=BA*Math.tan(FBC*Math.PI/180.0)*Math.tan(45.0*Math.PI/180.0)/(Math.tan(FBC*Math.PI/180.0)+Math.tan(45.0*Math.PI/180.0));
    BD=Dh/Math.sin(FBC*Math.PI/180.0);
    Dx=Bx+BD*Math.cos(FBC*Math.PI/180.0);
    Dy=By-BD*Math.sin(FBC*Math.PI/180.0);
    Eh=BA*Math.tan(FBC*Math.PI/180.0)*Math.tan(90.0*Math.PI/180.0)/(Math.tan(FBC*Math.PI/180.0)+Math.tan(90.0*Math.PI/180.0));
    BE=Eh/Math.sin(FBC*Math.PI/180.0);
    Ex=Bx+BE*Math.cos(FBC*Math.PI/180.0);
    Ey=By-BE*Math.sin(FBC*Math.PI/180.0);

    // 線分の長さ
    BD=Math.sqrt((Bx-Dx)*(Bx-Dx)+(By-Dy)*(By-Dy));
    DE=Math.sqrt((Dx-Ex)*(Dx-Ex)+(Dy-Ey)*(Dy-Ey));
    EF=Math.sqrt((Ex-Fx)*(Ex-Fx)+(Ey-Fy)*(Ey-Fy));

    // デバッグ用
    s += 'DE:EF:BD='+DE/EF+':1:'+BD/EF+', FBC='+FBC+'<br>';
    document.getElementById('inner').innerHTML = s;

    // 二分法
    if ( EF*2 > DE ) {
        AOCMax = AOC;
    } else if ( EF*2 < DE ) {
        AOCMin = AOC;
    }
}

 

随分と汚いソースだが、後々この座標を使って、キャンバスに描いていくことになるので、必要な値でもあります。

ループの最初の1行と、最後のif文が二分法の核心部分です。
最大値と、最小値の中間値をとって、その中間値を、次の最大値にするのか、最小値にするのか、このように反復して中間値を取り続けていくことで、正しい値に近似していきます。

二分法は2進数を扱うコンピュータには、とても親和性の高いアルゴリズムです。


さて、デバッグ用に吐き出したものを載せてみます。
 

DE:EF:BD=1.4142135623730963:1:3.4142135623730976, FBC=22.5
DE:EF:BD=4.027339492125835:1:20.24680287696229, FBC=11.25
DE:EF:BD=2.296558208938329:1:7.570737815980336, FBC=16.875
DE:EF:BD=1.794812772490478:1:5.01616566078543, FBC=19.6875
DE:EF:BD=2.027043204317777:1:6.135947356488646, FBC=18.28125
DE:EF:BD=1.9067857616655366:1:5.542617702555957, FBC=18.984375
DE:EF:BD=1.9658202440766486:1:5.830269476098221, FBC=18.6328125
DE:EF:BD=1.996150340320209:1:5.980766521480694, FBC=18.45703125
DE:EF:BD=2.011525415583937:1:6.057759913124062, FBC=18.369140625
DE:EF:BD=2.003820166621329:1:6.019115426779647, FBC=18.4130859375
DE:EF:BD=1.9999808414864075:1:5.9999042077990765, FBC=18.43505859375
DE:EF:BD=2.0018993990826393:1:6.009500603130066, FBC=18.424072265625
DE:EF:BD=2.00093984428897:1:6.004700104752151, FBC=18.4295654296875
DE:EF:BD=2.0004602739196766:1:6.002301581450466, FBC=18.43231201171875
DE:EF:BD=2.000220540464896:1:6.001102750962577, FBC=18.433685302734375
DE:EF:BD=2.0001006866665993:1:6.000503443470789, FBC=18.434371948242188
DE:EF:BD=2.0000407629992956:1:6.000203816658107, FBC=18.434715270996094
DE:EF:BD=2.0000108019735636:1:6.000054009984486, FBC=18.434886932373047
DE:EF:BD=1.9999958216626588:1:5.999979108330753, FBC=18.434972763061523
DE:EF:BD=2.000003311801286:1:6.0000165590173795, FBC=18.434929847717285
DE:EF:BD=1.9999995667277612:1:5.9999978336389885, FBC=18.434951305389404
DE:EF:BD=2.000001439263468:1:6.000007196319408, FBC=18.434940576553345
DE:EF:BD=2.00000050299535:1:6.000002514977007, FBC=18.434945940971375
DE:EF:BD=2.0000000348614897:1:6.000000174307452, FBC=18.43494862318039
DE:EF:BD=1.9999998007946047:1:5.9999990039730715, FBC=18.434949964284897
DE:EF:BD=1.999999917828049:1:5.999999589140238, FBC=18.434949293732643
DE:EF:BD=1.9999999763447662:1:5.999999881723827, FBC=18.434948958456516
DE:EF:BD=2.000000005603133:1:6.000000028015651, FBC=18.434948790818453
DE:EF:BD=1.9999999909739483:1:5.999999954869736, FBC=18.434948874637485
DE:EF:BD=1.999999998288539:1:5.999999991442694, FBC=18.43494883272797
DE:EF:BD=2.0000000019458337:1:6.0000000097291695, FBC=18.43494881177321
DE:EF:BD=2.0000000001171827:1:6.0000000005859215, FBC=18.43494882225059
DE:EF:BD=1.999999999202863:1:5.999999996014311, FBC=18.43494882748928
DE:EF:BD=1.999999999660029:1:5.999999998300133, FBC=18.434948824869934
DE:EF:BD=1.999999999888602:1:5.999999999443019, FBC=18.434948823560262
DE:EF:BD=2.0000000000028977:1:6.00000000001448, FBC=18.434948822905426
DE:EF:BD=1.9999999999457512:1:5.999999999728748, FBC=18.434948823232844
DE:EF:BD=1.9999999999743199:1:5.999999999871603, FBC=18.434948823069135
DE:EF:BD=1.9999999999886107:1:5.999999999943045, FBC=18.43494882298728
DE:EF:BD=1.9999999999957534:1:5.999999999978762, FBC=18.434948822946353
DE:EF:BD=1.999999999999324:1:5.999999999996617, FBC=18.43494882292589
DE:EF:BD=2.0000000000011067:1:6.000000000005535, FBC=18.434948822915658
DE:EF:BD=2.0000000000002216:1:6.000000000001092, FBC=18.434948822920774
DE:EF:BD=1.9999999999997657:1:5.999999999998838, FBC=18.43494882292333
DE:EF:BD=1.9999999999999922:1:5.999999999999962, FBC=18.434948822922053
DE:EF:BD=2.000000000000102:1:6.000000000000516, FBC=18.434948822921413
DE:EF:BD=2.0000000000000475:1:6.0000000000002425, FBC=18.434948822921733
DE:EF:BD=2.000000000000019:1:6.000000000000097, FBC=18.434948822921893
DE:EF:BD=2.000000000000009:1:6.000000000000037, FBC=18.434948822921974
DE:EF:BD=1.9999999999999964:1:5.999999999999989, FBC=18.434948822922014
DE:EF:BD=2.000000000000003:1:6.000000000000013, FBC=18.434948822921996
DE:EF:BD=2.000000000000004:1:6.00000000000001, FBC=18.434948822922003
DE:EF:BD=1.9999999999999962:1:5.999999999999989, FBC=18.43494882292201
DE:EF:BD=2.000000000000004:1:6.00000000000001, FBC=18.434948822922006
DE:EF:BD=1.9999999999999962:1:5.999999999999989, FBC=18.43494882292201
DE:EF:BD=1.9999999999999962:1:5.999999999999989, FBC=18.43494882292201
DE:EF:BD=1.9999999999999962:1:5.999999999999989, FBC=18.43494882292201
DE:EF:BD=1.9999999999999962:1:5.999999999999989, FBC=18.43494882292201
DE:EF:BD=1.9999999999999962:1:5.999999999999989, FBC=18.43494882292201
DE:EF:BD=1.9999999999999962:1:5.999999999999989, FBC=18.43494882292201
DE:EF:BD=1.9999999999999962:1:5.999999999999989, FBC=18.43494882292201
DE:EF:BD=1.9999999999999962:1:5.999999999999989, FBC=18.43494882292201
DE:EF:BD=1.9999999999999962:1:5.999999999999989, FBC=18.43494882292201
DE:EF:BD=1.9999999999999962:1:5.999999999999989, FBC=18.43494882292201

 

DE:EF:BDの移り変わりが見て取れるかと思います。
最後の10回は値が変化していませんね。
64回もまわす必要がなかったとも言えます。
最終的には、
DE:EF:BD=2:1:6
と言って遜色ない値になっているかと思います。

当然のことなのですが、近似値であるため、今回のような厳密解、厳密値を答えるような問題には向いておりません。

しかし、作図したり近似値を求めるということであれば、ある程度十分な精度が出ているとも言えることが分かって頂けるかと思います。


代数幾何で厳密解が求められていれば、プログラミングの方ももう少し簡単に作図出来ていたでしょう。

x=6、y=3から半円の半径は、ピタゴラスの定理で求まります。
角度が解らなくとも、辺の比から逆三角関数を使えます。
随分とアプローチが楽ですね。

こういうこともあるので、プログラミングをする前段階で、ある程度の数学的な考証が必要だということでもあります。


さて、数学には大きな3つの柱があります。
それは、代数学、幾何学、解析学の3つです。

代数幾何で解きましたが、方べきの定理は幾何学、連立方程式は代数学です。
プログラミングの中で使った二分法は解析学です。
作図をするには三角関数がかかせません。
距離を測るにはピタゴラスの定理がかかせません。

三角関数は幾何学的な側面もありますし、解析学的な側面もあります。
ピタゴラスの定理は幾何的な側面もありますし、代数的な側面もあります。

数学という一つの学問ではあるのですが、細分化され、組んず解れつしているのです。

コンピューター、プログラミングは応用数学の一つです。


自分は大学時代で数学科に居ましたが、数学科の学生それぞれに得意分野、不得意分野というものがありまして、これはどの分野でも同じことが言えるのではないでしょうか。

数学が出来る=プログラミングが出来る
数学が出来る⇒プログラミングが出来る

ということにはなりません。

ただ、コンピューターやスマホなどの画面上に絵を描くのにも、ある程度数学の知識が必要になります。
そういう意味では、数学を知らないとプログラミングは難しいということになってしまいますね。

ゲーム一つ作るのにも、変数があって、関数があって、変数の変化を場合分けで読み取って、ということは、どんなものを作るにしてもやることだと思います。

物事を順を追って論理的に感がられる⇒プログラミングが出来る

ということなのですが、命令には必ずと言っていいほど、数値が関わってきます。
そういう意味では算数や数学が必要になるかと思います。

あと何十年かしたら、数学の知識がまったく無くても、プログラミングが出来るというのが一般的になるのかもしれませんが、そうなったらプログラマーと呼べる人は増えるのかもしれませんが、質の良いプログラマーが多く育つのかと言われると、必ずしもそうとは言えません。

多少不便なくらいの方が、質の良いプログラマーは育つのではないかと、自分は考えております。


ではでは

 


Viewing all articles
Browse latest Browse all 5376

Trending Articles