ジャンケンで決着がつくまでの回数(4)

前回の、

(P(n, 1) + ... + P(n, n-1))E(n) = 1 + P(n, 1)E(n) + ... + P(n, n-1)E(n-1)

にしたがってプログラムを書くと、

E(2) = 1.5
E(3) = 2.2500000000000004
E(4) = 3.214285714285715
E(5) = 4.485714285714287
E(6) = 6.219815668202768
E(7) = 8.646735791090634
E(8) = 12.104443799363817
E(9) = 17.091935291769775
E(10) = 24.34959775845648
E(11) = 34.97946098669054
E(12) = 50.62502051675474
E(13) = 73.74035310886121
E(14) = 107.99313367330936
E(15) = 158.86844072976456

だいたい、1.5倍くらいずつになってるってことか。

E(3) / E(2) = 1.5000000000000002
E(4) / E(3) = 1.4285714285714286
E(5) / E(4) = 1.3955555555555556
E(6) / E(5) = 1.3865831107458397
E(7) / E(6) = 1.390191647526611
E(8) / E(7) = 1.3998859328899482
E(9) / E(8) = 1.4120380560293146
E(10) / E(9) = 1.4246249674360433
E(11) / E(10) = 1.4365519025685904
E(12) / E(11) = 1.4472784625245436
E(13) / E(12) = 1.4565989772676986
E(14) / E(13) = 1.4645052419789954
E(15) / E(14) = 1.4710976089494576
...
E(50) / E(49) = 1.4999667149758331
...

いったん下がって、また再び1.5に近づいている。

せっかくだから、分数表示も求めておこう。
前に作った分数オブジェクトを使って、

E(2) = 3/2
E(3) = 9/4
E(4) = 45/14
E(5) = 157/35
E(6) = 13497/2170
E(7) = 225161/26040
E(8) = 10007591/826770
E(9) = 200190574/11712575
E(10) = 25185528817258384/1034330384719049

最後はちょっとあやしいか?
C++で計算してみたら、やっぱり間違ってるみたい。
ソースは以下。



fraction.prototype.copy = fraction_copy;
fraction.prototype.add = fraction_add;
fraction.prototype.subtract = fraction_subtract;
fraction.prototype.multiply = fraction_multiply;
fraction.prototype.divide = fraction_divide;
fraction.prototype.normalize = fraction_normalize;
fraction.prototype.toString = fraction_toString;

function fraction(a, b) {
if(a == undefined) {
this.a = 0;
this.b = 1;
}
else if(b == undefined) {
this.a = a;
this.b = 1;
}
else {
this.a = a; // 分子
this.b = b; // 分母
this.normalize();
}
}

function fraction_copy() {
return new fraction(this.a, this.b);
}

function fraction_add(f) {
if(typeof f == "number") {
var b = this.b;
return new fraction(this.a + b * f, b);
}
else if(f instanceof fraction) {
var b = this.b;
var f_b = f.b;
return new fraction(this.a * f_b + b * f.a, b * f_b);
}
else
throw("wrong argument in fraction::add");
}

function fraction_subtract(f) {
if(typeof f == "number") {
var b = this.b;
return new fraction(this.a - b * f, b);
}
else if(f instanceof fraction) {
var b = this.b;
var f_b = f.b;
return new fraction(this.a * f_b - b * f.a, b * f_b);
}
else
throw("wrong argument in fraction::add");
}

function fraction_multiply(f) {
if(typeof f == "number")
return new fraction(this.a * f, this.b);
else if(f instanceof fraction) {
var r1 = new fraction(this.a, f.b);
var r2 = new fraction(f.a, this.b);
r1.a *= r2.a;
r1.b *= r2.b;
return r1;
}
else
throw("wrong argument in fraction::add");
}

function fraction_divide(f) {
if(typeof f == "number")
return new fraction(this.a, this.b * f);
else if(f instanceof fraction)
return new fraction(this.a * f.b, this.b * f.a);
else
throw("wrong argument in fraction::add");
}

function fraction_normalize() {
// ユークリッドの互除法
var a = this.a;
var b = this.b;
var a2, f;
while(true) {
if((a2 = a % b) == 0) {
f = b;
break;
}
if((b %= a) == 0) {
f = a;
break;
}
a = a2;
}
this.a /= f;
this.b /= f;
if(this.b < 0) {
this.a = -this.a;
this.b = -this.b;
}
}

function fraction_toString() {
if(this.b == 1)
return this.a;
else
return this.a + "/" + this.b;
}

var E = [ new fraction(), new fraction() ];

for(var n = 2; n <= 10; n++) {
E[n] = new fraction(1);
var P = [ frac_pow(new fraction(1, 3), n - 1) ];
P[n] = new fraction(1);
for(var k = 1; k < n; k++) {
P[k] = P[k-1].multiply(new fraction(n - k + 1, k));
P[n] = P[n].subtract(P[k]);
E[n] = E[n].add(P[k].multiply(E[k]));
}
E[n] = E[n].divide( (new fraction(1)).subtract(P[n]));
print("E(" + n + ") = " + E[n]);
}

function frac_pow(f, n) {
var ret = new fraction(1);
for(var i = 0; i < n; i++)
ret = ret.multiply(f);
return ret;
}

function print(str) {
WScript.Echo(str);
}