さて、昨日の記事のきっかけになったプログラムのことについて書いてみる。
とは言っても、プログラムの話しというよりも、数学の話しになると思われる。
数学の図形問題で有名なものに、ラングレーの問題というのがある。
私も何度も記事を書いているだろう。
ameba owndでも、書いてるね。
https://knife1968.amebaownd.com/posts/3731603
owndで作っている、この画像を使って説明しよう。
ある凸四角形を描き、対角線を引く。
左上の頂点から反時計回りに、A、B、C、Dとし、
α=∠ABD
β=∠DBC
γ=∠ACB
δ=∠ACD
として、α、β、γ、δは度数法における自然数が与えられるとき、
θ=∠ADB
を求めよという問題である。
エドワード・マン・ラングレー(1851-1933)という数学者が
α=20˚、β=60˚、γ=50˚、δ=30˚
という問題を出題したので、ラングレーの問題と呼ばれる。
また、このα、β、γ、δを一般化したものを、
フランクリンの凧、
正角四角形問題、
などと呼ぶ。
整数であること、図形問題としてバリエーションが豊富なこと、初学者でもパズル的要素があって取っつきやすい、などなどの理由から親しまれている問題である。
Javascript+HTML5などで、綺麗な図形を描くことは、実はそれほど難しくはない。
つまり、θの値は関数電卓とかを使えば求まるのだが、そのように解くのはあまりエレガントではない。
補助線を引いたりして、既知の図形の性質などを使って、四則演算程度の簡単な計算で求めるのがエレガントなのである。
三角形の内角の和は180˚とか、
三角形の底角が等しいから二等辺三角形になるとか、
三角形の2つの内角が60˚なので、正三角形だから三辺が等しいとか、
三辺が等しいから、内角は60˚とか、
対角の和が180˚だから、円に内接するとか、
円に内接するから、円周角が等しいとか、
本当に誰でも知っている初等的な解き方で解けるとかっこいいのである。
あとは誰も知らないような解き方で解けるのもかっこいいのである。
この問題を解くアプローチの仕方はたくさんある。
たくさんあるので、それをAIに学習させて、未知の問題を解かせるなんてことも出来るかとは思う。
ただ、AIだからといってもすべてブラックボックスにしてしまっては数学の発展にはつながらない。
出来れば、なぜそのようなアプローチをしたのかまで追跡出来るようにしてほしいところだろう。
さて、私はC言語で逆三角関数を使って求めることをやろうとしたわけです。
解いたわけじゃないです。
計算で求めただけです。
それで、昨日の記事になったわけです。
プログラムのソースは、
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[])
{
int i,j,k,l,m;
long double a,b,c,d,e;
long double p=3.14159265358979323846264338327950288419716939937510;
if ( argc != 5 ) return EXIT_SUCCESS;
i = atoi(argv[1]);
j = atoi(argv[2]);
k = atoi(argv[3]);
l = atoi(argv[4]);
a = tanl(p*k/180.0L)/(tanl(p*(i+j)/180.0L)+tanl(p*k/180.0L));
b = tanl(p*j/180.0L)/(tanl(p*(k+l)/180.0L)+tanl(p*j/180.0L));
c = a*tanl(p*(i+j)/180.0);
d = b*tanl(p*(k+l)/180.0);
e = -atan2l(d-c,1-a-b)*180.0/p+(long double)j;
m = lroundl(e);
printf("%d %d %d %d %d\n",i,j,k,l,m);
printf("%%lf\t%.50lf\n",(double)e);
printf("%%le\t%.50le\n",(double)e);
printf("%%lg\t%.50lg\n",(double)e);
return EXIT_SUCCESS;
}
コンパイルオプションは何も付けていません。
-mlong-double-80 は付けても構いませんが、-64や-128では私のWIndows10環境ではバグります。
-ansi は付けないです。付けると私の環境ではバグります。
実行ファイルは langray.exe として話しを進めます。
langray 20 60 50 30
のように、α、β、γ、δの値をパラメータで与えます。
20 60 50 30 30
のように、α β γ δ θ と並んで表示されます。
θの値が正しくなればいいのですが、ラングレーの問題の答えも整数なのです。
しかし、計算はゴリゴリと浮動小数点型なんです。
ですので、小数点以下がどうなっているのか。
.999999…
のように続いていたり、
.000000…1
といったように、0が続いたあとにちょっとした値があったり、
こういう誤差をどこまで認めるのかという問題になるんだろうと思っています。
というわけで、"%lf"、"%le"、"%lg"の3種類でθ(プログラム内では変数e)を出力しています。
浮動小数を扱うということは、誤差との戦いなわけです。
さて、数学的なところでは、私は正角四角形問題は、先のowndでもやっているとおり、
α、β、γ、δの最大公約数、ないし約数をθが持つ。
と私は考えている。
ナイフの仮説、とでもしておきましょうかw
ラングレーの問題は、
α=20、β=60、γ=50、δ=30であるから、
gcd(α,β,γ,δ)=10
なので、θは10を約数に持つ。だろうと考えています。
つい最近、新たな正角四角形問題を見かけた。
α=42、β=42、γ=30、δ=54
さて、θは何度だろうか。
さてさて、簡単に答えを求められるプログラムが出来たのだが、浮動小数を扱っているから、思わぬところからトラブるかもしれません。
langray 20 60 50 30
langray 42 42 30 54
は、誤差が出ていません。
誤差が出るものをあげると、
.000000系誤差
langray 20 30 80 60
langray 10 10 100 50
.999999系誤差
langray 100 50 20 30
ではでは