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

(x+y+z)(1/x+1/y+1/z)=n

$
0
0

今度はプログラミングの話しです。



(x+y+z)(1/x+1/y+1/z)=n
x, y, z, n∈N

上記を満たす、x, y, z, nを列挙するプログラムを作るのだが、どうするのが良いのか。

例えば、nを与えて、x, y, zを出力するとして、必ず見つかるものなのだろうか?
プログラミング言語であるから、変数の取り得る範囲があって、その有限の中で見つかるものだろうか。

先の数学の話しの中でも登場したが、
x≦y≦z
gcd(x, y, z)=1
という条件を付け加える。

さすれば、
x≦y≦z<fin
のようなfinを与えることも出来る。

これが妥当だろうか。

fin=10のとき、7個
fin=100のとき、21個
fin=1000のとき、46個


この少なさです。
高速化を目指すのであれば、画期的な方法を見つける必要がありそうですね。

まぁ、そんな簡単にみつかるとは思えない。

まずはたたき台。
x, y, zの3重ループになるのだが、yをx, zで挟む形で、一番内側に持ってくるだろう。

for (z=1; z<fin; z++) {
    for (x=1; x<=z; x++) {
        xz = (x+z)*x*z;
        for (y=x; y<=z; y++) {
            if ( xz%y ) continue;
            u = (x+y+z)*(x*y+x*z+y*z);
            l = x*y*z;
            if ( u%l > 0 ) continue;
            printf("%d\t%d\t%d\t%d\n", u/l, x, y, z);
        }
    }
}

こんな感じ。

まぁ、zが大きくなるにつれ、なかなか新しい答えが出てこないというものだから、あえてgcdを取らないで出力させてた。

しかし、x=y=zが毎回出てくるのもなんなんで、

for (z=1; z<fin; z++) {
    for (x=1; x<z; x++) {
        xz = (x+z)*x*z;
        for (y=x+1; y<z; y++) {
            if ( xz%y ) continue;
            u = (x+y+z)*(x*y+x*z+y*z);
            l = x*y*z;
            if ( u%l > 0 ) continue;
            printf("%d\t%d\t%d\t%d\n", u/l, x, y, z);
        }
    }
}

と=を抜いても良いだろう。
それによって弾かれるのは、導入問題でやった、
n=9, x=1, y=1, z=1
n=10, x=1, y=1, z=2
n=10, x=1, y=2, z=2
だけである。

さて、数学で考えたなかに、
x1:z1=x2:z2
と整数比が等しい組(x1, y1, z1), (x2, y2, z2)は、
外項の積と内項の積は等しいより、

x1・z2=x2・z1
となり、さらに
x1・z2=x2・z1=y1・y2
となります。

n=1のとき、(x, y, z)=(1, 1, 1)
と1つしかないケースも、上記の式は成り立つので、
y1とy2の小さな方だけをプログラムで見つけ、
もう一方は別のプログラムで計算させるという方法もある。

安直に、変数cをカウンターとして、

for (z=1; z<fin; z++) {
    for (x=1; x<z; x++) {
        xz = (x+z)*x*z;
        for (c=0, y=x; c<1 && y<z; y++) {
            if ( xz%y ) continue;
            u = (x+y+z)*(x*y+x*z+y*z);
            l = x*y*z;
            if ( u%l > 0 ) continue;
            printf("%d\t%d\t%d\t%d\n", u/l, x, y, z);
            c++;
        }
    }
}

とやってしまいたいところでもある。

ただ、すべての(x, z)の間に、yがあるかというと、無い場合が殆どであるから、枝刈りとしては不十分だろうか。

y1≦y2として、イコールは重解であり、重解以外は大小関係が存在する。
重解の場合は、(x, y, z)が等しいので、sqrt(x*z)=yであり、

for (z=1; z<fin; z++) {
    for (x=1; x<z; x++) {
        xz = (x+z)*x*z;
        sq = sqrt(x*z)+0.5;
        for (c=0, y=x; c<1 && y<sq; y++) {
            if ( xz%y ) continue;
            u = (x+y+z)*(x*y+x*z+y*z);
            l = x*y*z;
            if ( u%l > 0 ) continue;
            printf("%d\t%d\t%d\t%d\n", u/l, x, y, z);
            c++;
        }
    }
}

とすれば、多少は高速に動くだろうか。

yの片割れをプログラミングでやろうとすると、小数を扱ってやることになるのだろうか。
あんまりよろしく無いな。
そっちの方も考えなきゃね。


ではでは


Viewing all articles
Browse latest Browse all 5376

Trending Articles