大きい数が出やすいサイコロ関数

課題

例えば最小値1,最大値5のとき

1,2,2,3,3,3,4,4,4,4,5,5,5,5,5といった

数字と出やすさが比例する15面体のサイコロを想定して出目を出力する関数を作る。

 

 

素直な解

int x = rand(15);

write(f(x));

 

function f(x) {

int y = 0;

while (x > 0)

{

x -= ++y;

}

return y;

 

 

公式で

たしかに上記でもできたけど、できればループより式で一発解答したいものです。

当方のサビついた頭では難しそうと思い込みいろいろ考えた末、実は中学レベルの問題だったことに気付いて愕然とした。

 

y||x

....

3||4|5|6|

2||2|3|

1||1|

 

3段目の例でいえばxが4~6のときyが3になるような式を作れば良いことがわかる。

ということで右端の値だけに着目すると

y||x

....

3||6|=1+2+3

2||3|=1+2

1||1|=1

これはx={y(y+1)}/2で表せる式である。

これをyについて解く必要がある。

まず展開すると

x=1/2y^2+1/2y

2倍して

2x=y^2+y

y^2+y-2x=0

あらためて2次方程式の解の公式を使いyについて解くと

y={-1±√(1+8x)}/2

ただしここでいうxはyに対応する最大値なので、小数点以下の端数が出た場合は切り上げることになる。

式 y=ceil({-1±√(1+8x)}/2)

 

c# double y = Math.Ceiling((-1 + Math.Sqrt(1 + 8 * (double)x)) / 2);