まだ、この問題に取り組んでいます。
今回は、今までの考え方をやめて、アプローチを変えました。
なんでかというと、今までの方法は間違っていて、そこを直したら遅すぎたから。
x≦y≦z
という条件にしても一般性を失わないことから、xとyを決めて、yをその範囲で動かすということで、
x≦y≦z<fin
という終了条件まで見つけるということをやっていました。
今までの方法のたたき台のソースは、
for (z=1; z<fin; z++) {
for (x=1; x<=z; x++) {
for (y=x; y<=z; y++) {
/* x, y, zからnを求めて、nが整数になるかを判定 */
}
}
}
枝刈りをしていない状態が、こんなようなネストになります。
sqxz = sqrtl(x*z)+0.5L;
for (y=x; y<sqxz; y++) {
}
のような、yのレンジの枝刈りや、
for (y=x, c=0; y<sqxz && c<1; y++) {
/* yが見つかったらc++ */
}
のような、yの片割れだけを見つけるとかやってました。
が、この方法には問題がありました。
どんな問題かというと、
x≦sqrtl(x*z)≦z
のようにsqrtl(x*z)で二分して、前半だけしか調べていない。
finのレンジにおいて、後半にyの答えがあって、前半はfinのレンジの外にあるということがあるからです。
例えば、fin=100として検索させたとして、
x=1, y=35, z=90, n=131は、
sqrtl(x*z)≒9.48で、y=35はsqrt(x*z)より後に出現する。
片割れは、
x=7, y=18, z=630, n=131で、
sqrtl(x*z)≒66.40で、y=18はsqrt(x*z)より前に出現する。
つまり、
for (y=x; y<sqxz; y++) {
}
という枝刈りでは上記データは盲点になって、fin=100では見つけられないのである。
よって、
for (y=x, c=0; y<=z && c<1; y++) {
}
という枝刈りを採用せざるを得ない。
これは、finが大きくなればなるほど、時間を要することになるので、私の構想としてはfin=10万くらいまでは求めたいという欲求は、何ヶ月も掛かってしまうことだろう。
プログラムがくそ遅いので、その分時間があったので他の方法を考えてみた。
xとzが定まれば、nのレンジも定まるのではないだろうか?
yの取り得る範囲は、xからzまで。
つまり、y=x、y=z、y=sqrt(x*z)のときの、nの値を求めてみよう。
n=(x+y+z)(1/x+1/y+1/z)
y=xのとき、
n=(2x+z)(2/x+1/z)=(2x+z)((x+2z)/xz)=(2x+z)(x+2z)/xz
y=zのとき、
n=(x+2z)(1/x+2/z)=(x+2z)((2x+z)/xz)=(2x+z)(x+2z)/xz
と、同じ値になる。
y=sqrt(xz)のとき、
n=(x+z+sqrt(xz))(1/x+1/z+1/sqrt(xz))
大小関係は、
(x+z+sqrt(xz))(1/x+1/z+1/sqrt(xz))≦n≦(2x+z)(x+2z)/xz
nは整数なので、
⌈(x+z+sqrt(xz))(1/x+1/z+1/sqrt(xz))⌉≦n≦⌊(2x+z)(x+2z)/xz⌋
と、前者を天井関数、後者を床関数で括ることができる。
nのレンジが定まりました。
x, z, nからyを求める方法を考えます。
n=(x+y+z)(1/x+1/y+1/z)
=(x+y+z)(xy+xz+yz)/xyz
nxyz=(x+y+z)(xy+xz+yz)
nxyz=x2y+x2z+xyz+xy2+xyz+y2z+xyz+xz2+yz2
yの方程式にする。
(x+z)y2+(x2+z2-(n-3)xz)y+(x2z+xz2)=0
(x+z)y2+(x2+z2-(n-3)xz)y+(x+z)xz=0
a=x+z
b=x2+z2-(n-3)xz
c=(x+z)xz
2次方程式の解の公式ですね。
d=b2-4ac
dが負になることで枝刈りできます。
また、yは整数になるには、dは平方数である必要があります。
平方数判定は出来ますが、さらにネストを増やすのでやめました。
a, b, c, dは小数として計算して、
sqd = sqrtl(d);
y1 = 0.5L+(-b+sqd)/(2.0L*a);
y2 = 0.5L+(-b-sqd)/(2.0L*a);
と二つの解を求め、x, y, zからnを計算して判定すればよい。
この方法でプログラムを組んでみたら、めちゃくちゃ高速でした。
体感で100倍くらいは速い。
これならfin=10万も、現実味が出てきました。
64ビットで計算が収まるならfin=100万も行けるかな?
ではでは