読者です 読者をやめる 読者になる 読者になる

Tips

IT技術系Tips

数学わかんねーからプログラムでズルしてみた 1次方程式編(Python:Sympy)

最近Smiteってゲームにハマってて、これの勝率が気になった。
基本5:5で戦うゲームなんだけど、マッチングシステムがよく出来てて、長いことやってるとだいたい勝率が50%くらいになるようになってる。

現在の戦績が1190戦610勝580負。
勝率51%くらい。
さぁ、何連勝したら勝率52%になるんでしょうか!

今後の戦闘回数 = 今後の勝利回数 = xとすると、こんな感じ

(610 + x) / (1190 + x) = 0.52

sympyで書くとこう

In [1]: solve(Eq((610 + x) / (1190 + x), 0.52))
Out[1]: [18.3333333333333]

方程式は解が複数あったりもするから配列で答えが返ってくるんだね。
戦う回数に小数とか無いから切り上げて

In [2]: solve(Eq((610 + x) / (1190 + x), 0.52))[0].ceiling()
Out[2]: 19

はい、19連勝すれば勝率52%を超えます!

勝率51%の自分がストレートに19連勝できる確率は

0.51 ^ 19

これをpython(sympy)で書くと

In [3]: 0.51**19
Out[3]: 2.778646798186872e-06

指数とかよくわかんない。
新人の頃、計算結果を指数表記で出してお客さんに「こんなんわけわからんわ!」と、怒られたことがある。
わざとやったわけじゃないんだけどね、PostgreSQLの列定義をfloatにしててそのまま出力してたら出ちゃってね・・・。
なんて苦い経験があるから指数表記をやめる。

※変数aはpythonのbuiltinのfloatなんで、sympyのFloatにしてevalf使って桁数指定した。

In [4]: a=0.51**19

In [5]: Float(a).evalf(50)
Out[5]: 0.0000027786467981868720860121231563955035426261019892991

はい、まだよくわかんない。

分数にしよう。

In [6]: Rational(a)
Out[6]:
   3280447126872685
──────────────────────
1180591620717411303424


わかんねぇよ!!
つーかほんとかよこれ。
ドキュメントを見てみると
SymPy Core — SymPy 0.7.6.1 documentation

If the simpler representation of the float is desired then consider limiting the denominator to the desired value or convert the float to a string (which is roughly equivalent to limiting the denominator to 10**12):

ふむ、文字列にするか分母を制限しろとか書いてある。

In [7]: Rational(str(b))
Out[7]:
   277864679818687
─────────────────────
100000000000000000000

そろそろ自分が何をしたいのかわかんなくなってきた。

あー、そうだ。
勝率51%の自分がストレートに19連勝できる確率は「1/1000 くらい!」とか適当な感じで表して嘆きたかったんだ。

もういいよ。

In [3]: 0.51**19
Out[3]: 2.778646798186872e-06

なんだから

3/100万くらいっしょ?
それとも分母を制限してこんな感じのがまし?

In [8]: ra = Rational(str(b))
In [9]: ra.limit_denominator(1/a)
Out[9]: 1/359887

最初からわかってたけど、sympy使いこなしてないならwindows付属の関数電卓と紙でやったほうが断然早いよね。
でもlimit_denominatorはちょっと好き。
この関数見つけたのは嬉しい。