スポンサーリンク
※サイト運営にサーバーは必須です※
~このサイトもエックスサーバーを使用しています~
目次
はじめに
※目次用の記事:ギャンブルの賭け方の種類をまとめてみた
賭け方の一つとして、パーレー法というのがある。
一言で言えば、勝った時にかけ金を2倍に増やしていく方法だ。
負けた時に2倍にかけ金を増やしていくマーチンゲール法と真逆のため、逆マーチンゲール法(アンチマーチンゲール法)と呼ばれることもある。
この記事では、パーレー法のシミュレーションを取り扱い、検証する。
パーレー法とは
最小の賭け金額を自分で設定し、最初はこの最小の賭け金額からスタートする。
また、何連勝したらゲームをリセットするか自分で設定する。
負けた場合:次の勝負の賭け金は、設定した最小の賭け金額に戻す
勝った場合:次の勝負の賭け金は、現在賭けている2倍の金額にする(ただし、設定した連勝が達成できた場合、最小の賭け金額に戻す)
パーレー法の具体例
ルールだけ、説明してもイメージがつかめないと思うので、具体例を挙げる。
勝率が50%で払戻金が2倍の勝負として、コインの表裏の賭けなどをイメージしてください。
また、5連勝したら、いったん賭け金を最小額に戻すとする。
もしも5連勝したら、以下のテーブルのように賭け金を
1→2→4→8→16
と増やしていく
勝敗 | 賭け金 | 累計損益 |
○ | 1 | 1 |
○ | 2 | 3 |
○ | 4 | 7 |
○ | 8 | 15 |
○ | 16 | 31 |
最終的な利益は+31となる
次に、途中で負けた場合を考える。
例として、4連勝した後、負けた時を考察する。
勝敗 | 賭け金 | 累計損益 |
○ | 1 | 1 |
○ | 2 | 3 |
○ | 4 | 7 |
○ | 8 | 15 |
× | 16 | -1 |
このように、万が一途中で負けた場合は、どんなに途中で勝っていても、最終的な損益は-1となる。
つまり、連勝して勝負を一度リセットできれば、利益が十分確保できる。だが、負ければ、途中の過程がどうであれ、今までの利益が吹っ飛んだ上に-1される。
期待値検証
直観的に考えてもわかるが、勝負して得られる利益の期待値は0である
連勝回数 | 確率 | 累計利益 | 期待値 |
0 | 0.5 | -1 | -0.5 |
1 | 0.25 | -1 | -0.25 |
2 | 0.125 | -1 | -0.125 |
3 | 0.0625 | -1 | -0.0625 |
4 | 0.03125 | -1 | -0.03125 |
5 | 0.03125 | 31 | 0.96875 |
期待値合計 | 0 |
連勝回数0は負けを意味し、確率は1/2
連紹回数1は、2連勝ではないが、1度勝利する確率を意味し
1/2-1/4で1/4(0.25)となる
連勝回数4は、5連勝ではないが、4連勝する確率を意味し、
1/32-1/16=1/32
最後の5連勝の部分は、そのまま5連勝できる確率。
(正確に言えば5連勝以上できる確率)
1/2を5乗した1/32
それぞれの事象が起こる確率に累計利益をかけて、その期待値を取るとゼロになる。
パーレー法の検証
以下では2つのプログラムを紹介する。
言語はC++で作ったが、C言語としてコンパイルしても動くと思う
※このプログラムを組んだ人間は、大学時代に少しプログラムをかじった程度の戦闘能力しかない
パーレー法の個別シミュレーション
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> int main() { int i=0; int i_max=100000;//勝負回数(2147483647まで指定か) double w=2.0; //賭け金の変換率(2倍以上)(win) double p=50; //勝率(50%以下)(probability) double m_min=1;//最小の賭け金額(money) double m_int=1000;//最初の手持ちの資金(money_initial) int c; c=0;//初期化 int c_max=5;//何連勝でおりるか?(count) //乱数(時間による変化) srand((unsigned)time(NULL)); //ファイルの出力準備 FILE *sf; sf = fopen("simulation.dat","w");//出力するファイルの名前を指定 //エラー if(sf==NULL){ printf("ファイルオープンエラー\n"); return -1; } //初期条件の表示 printf("#倍率は%lf\t勝率は%lf\t最小の賭け金は%lf\t手持ちのお金は%lf\n",w,p,m_min,m_int); fprintf(sf,"#倍率は%lf\t勝率は%lf\t最小の賭け金は%lf\t手持ちのお金は%lf\n",w,p,m_min,m_int); double m_now;//現在の資金 double m_bet;//賭け金 //初期化 m_bet=m_min;//最初は最小の賭け金でスタート m_now=m_int;//最初は最初の手持ちの資金でスタート for(i=1;i<=i_max;i++) { double r;//乱数(rand) r=100.0*rand()/(RAND_MAX+1.0);//0から100の乱数を出す if (p<=r){//負けの場合 m_now=m_now-m_bet; m_bet =m_min;//賭け金を最小額に戻す c=0; } else{//勝ちの場合 m_now =m_now+m_bet*(w-1.0); m_bet =m_bet*2;//賭け金を2倍に c+=1; } if(c==c_max){ m_bet =m_min; c=0; } printf("%d回目\t賭け金は%lf\t手持ちのお金は%lf\n",i,m_bet,m_now); fprintf(sf,"%d回目\t賭け金は%lf\t手持ちのお金は%lf\n",i,m_bet,m_now); if(m_now<m_bet){//手持ちの金より賭けるお金が高い場合 printf("%d回目で手持ちのお金が足りません\n",i); fprintf(sf,"%d回目で手持ちのお金が足りません\n",i); break; } }//for(i)文の終わり //sfクローズ fclose(sf); return 0; }//プログラムの終わり |
変数の定義はマーチンゲール法(2倍賭け)の破綻までのシミュレーションで紹介したプログラムと基本的に同じ。
i_maxで勝負の回数を指定
wでは、賭けたお金の戻る倍率を指定。ここでは2倍を指定
pで勝率を指定、ここでは半々の確率なので50。
m_minでかけ金を指定。m_intで手持ちの軍資金を指定
※初期(initial)のスぺルを自分が勘違いしていたことに後から気が付いた。だが、プログラムと記事を今からすべて手直しするのはしんどいので、時間があったら、宣言する変数の名前をm=intからm_iniに書き替えたい。……文章を書いている人間の英語力の低さがばれて、地味に恥ずかしい。
ここではm_min=1でm_int=1000と、最小の賭け金の1000倍を所持していると考えている。
例えば、最小の賭け金が1000円(千円)だとするなら、手元の軍資金は、1000000円(百万円)。割と現実的な設定だと思われる。
0~100の乱数rを振って、乱数rが勝率pより下の数で収まるなら勝ちの判定がでる。
イメージそしては勝率が30だった場合、乱数をふって5、12、29のような30より下回れば、勝ち。(p>r )31、45、62、98のように30以上だった場合は負け判定が出る。(p<=r)
そして、勝負を続けていくうちに、負け続けることもあるだろう。
そしてついに、手持ちのお金が足りなくなるかもしれない。
この場合、これ以上勝負ができなくなり、プログラムは終了する。(破綻判定)
つまり、借金はNG。
※以下、マーチンゲール法になかった要素
パーレー法は、何連勝したら、いったん最小の賭け金に戻すか決める必要がある。
その指定をc_maxで行い、ここではc_max =5として、5連勝した場合いったんリセットする。
Int cは現在何連勝しているかカウントするために用意されている
実際にプログラムを走らせると以下のような結果となる
勝負回数i_maxは100000(10万回)までとする
※ここで、表示される「賭け金」の意味は、「次の勝負に必要な賭け金」という意味で使われている。(ちょっとわかりづらいかも……)
#倍率は2.000000 勝率は50.000000 最小の賭け金は1.000000 手持ちのお金は1000.000000
1回目 賭け金は2.000000 手持ちのお金は1001.000000
2回目 賭け金は1.000000 手持ちのお金は999.000000
3回目 賭け金は2.000000 手持ちのお金は1000.000000
4回目 賭け金は4.000000 手持ちのお金は1002.000000
(省略)
99998回目 賭け金は1.000000 手持ちのお金は1481.000000
99999回目 賭け金は2.000000 手持ちのお金は1482.000000
100000回目 賭け金は1.000000 手持ちのお金は1480.000000
10万回まで勝負がまででき、元のお金(1000)よりも増えて1480という結果に。
srand((unsigned)time(NULL));の部分で時間を参照した上で乱数を発生させている。
そのため、実行するタイミングで結果が変化する。
ちなみに、途中でお金が無くなる場合は以下のような結果が表示される
(省略)
54925回目 賭け金は1.000000 手持ちのお金は1.000000
54926回目 賭け金は1.000000 手持ちのお金は0.000000
54926回目で手持ちのお金が足りません
パーレー法の期待値シミュレーション
上のプログラムを何度も走らせて期待値や破綻する率をもとめたい
そのためのプログラムは以下のようになる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> int main() { int k; int k_max=20000;//試行回数 int i=0; int i_max=100000;//勝負回数 double w=2.0; //賭け金の変換率(2倍以上)(win) double p=50; //勝率(50%以下)(probability) double m_min=1;//最小の賭け金額(money) double m_int=1000;//最初の手持ちの資金(money_initial) int b;//破たん回数のカウント(Bankruptcy) b=0;//初期化 int i_sum;//勝負回数の合計 double m_sum;//最終的なお金の合計 i_sum=0;//初期化 m_sum=0.0; //乱数(時間による変化) srand((unsigned)time(NULL)); //ファイルの出力準備 FILE *sf; sf = fopen("simulation.dat","w");//出力するファイルの名前を指定 //エラー if(sf==NULL){ printf("ファイルオープンエラー\n"); return -1; } //初期条件の表示 printf("#倍率は%lf\t勝率は%lf\t最小の賭け金は%lf\t手持ちのお金は%lf\n",w,p,m_min,m_int); fprintf(sf,"#倍率は%lf\t勝率は%lf\t最小の賭け金は%lf\t手持ちのお金は%lf\n",w,p,m_min,m_int); for(k=1;k<=k_max;k++) { int i_cout;//勝負回数のカウント(カウントのスペルが間違っている) i_cout=0; int c; c=0;//初期化 int c_max=5;//何連勝でおりるか?(count) double m_now;//現在の資金 double m_bet;//賭け金 //初期化 m_bet=m_min;//最初は最小の賭け金でスタート m_now=m_int;//最初は最初の手持ちの資金でスタート for(i=1;i<=i_max;i++) { double r;//乱数(rand) r=100.0*rand()/(RAND_MAX+1.0);//0から100の乱数を出す if (p<=r){//負けの場合 m_now=m_now-m_bet; m_bet =m_min;//賭け金を最小額に戻す c=0; } else{//勝ちの場合 m_now =m_now+m_bet*(w-1.0); m_bet =m_bet*2;//賭け金を2倍に c+=1; } if(c==c_max){ m_bet =m_min; c=0; } i_cout=i;//i_coutを定義しないと破たんしない(セーフ)場合、iと値が1ずれてしまうため if(m_now<m_bet){//手持ちの金より賭けるお金が高い場合 break; } }//for(i)文の終わり if(i_cout<i_max) { printf("%d番目%d回目で破たん\t手持ちのお金は%lf\n",k,i_cout,m_now); fprintf(sf,"%d番目%d回目で破たん\t手持ちのお金は%lf\n",k,i_cout,m_now); b=b+1; } else{ printf("%d番目\t%d回目までセーフ\t手持ちのお金は%lf\n",k,i_cout,m_now); fprintf(sf,"%d番目\t%d回目までセーフ\t手持ちのお金は%lf\n",k,i_cout,m_now); } i_sum=i_sum+i_cout; m_sum=m_sum+m_now; }//for(k)文の終わり //破たん率 printf("勝負回数は%d\n",i_max); printf("試行回数は%d\n",k_max); printf("破たん回数は%d\n",b); fprintf(sf,"勝負回数は%d\n",i_max); fprintf(sf,"試行回数は%d\n",k_max); fprintf(sf,"破たん回数は%d\n",b); double b_pro= (double)b/(double)k_max*100.0;//(double)を抜くとb/k_maxがゼロと評価されてしまう printf("破たん率は%lf%\n",b_pro); fprintf(sf,"破たん率は%lf%\n",b_pro); double i_exp=(double)i_sum/(double)k_max; double m_exp=(double)m_sum/(double)k_max; printf("破たんするまでに行える勝負回数の期待値(i_exp)は%lf\n",i_exp); printf("破たんする直前で持っているお金の期待値(m_exp)は%lf\n",m_exp); fprintf(sf,"破たんするまでに行える勝負回数の期待値(i_exp)は%lf\n",i_exp); fprintf(sf,"破たんする直前で持っているお金の期待値(m_exp)は%lf\n",m_exp); //sfクローズ fclose(sf); return 0; }//プログラムの終わり |
上のプラグラムになかった要素として
破綻率b_proを求める
※ここでいう破綻率とは手持ちのお金が、次の勝負に耐えられない状況を意味する。借金してお金を用意することはできないとする。
破綻するまで何回勝負ができるかの期待値であるi_exp
※もしも、指定した勝負回数が終了した段階で、破綻しなかった場合は、指定した勝負回数の値が、期待値算出のために使われる
勝負が終わった段階で持っているお金の期待値m_exp
期待値を求めるために何回試行するかを決めるk_max
k_maxを大きくすればするほど、正確な値が求まる。
ここでは、試行回数k_maxを20000(2万回)、勝負回数は100000(10万回)
#倍率は2.000000 勝率は50.000000 最小の賭け金は1.000000 手持ちのお金は1000.000000
1番目 100000回目までセーフ 手持ちのお金は1058.000000
2番目82873回目で破たん 手持ちのお金は0.000000
(省略)
19997番目65184回目で破たん 手持ちのお金は0.000000
19998番目11842回目で破たん 手持ちのお金は0.000000
19999番目33805回目で破たん 手持ちのお金は0.000000
20000番目 100000回目までセーフ 手持ちのお金は1796.000000
勝負回数は100000
試行回数は20000
破たん回数は8472
破たん率は42.360000%
破たんするまでに行える勝負回数の期待値(i_exp)は77169.467600
破たんする直前で持っているお金の期待値(m_exp)は995.348800
10万回勝負すると、42.360000%の確率で途中でお金がなくなり0になる。
持ち金の期待値は、995.348800とほぼ1000。
パーレー法で一回当たり、得られる利益の期待値は所詮ゼロなので、この結果は納得できる。
パーレー法は連勝回数を3か5で止めるのが一般的という噂を聞いた。
そこで、c_max を5から3にして、3連勝で勝負をストップさせるとすると以下のような結果になった。
勝負回数は100000
試行回数は20000
破たん回数は2297
破たん率は11.485000%
破たんするまでに行える勝負回数の期待値(i_exp)は96247.342200
破たんする直前で持っているお金の期待値(m_exp)は998.618950
破綻率は11.48%ほど
結果考察
かつて、マーチンゲール法でも同じようなシミュレーションをしたことがある。
(グラン)マーチンゲール法において、10万回勝負した場合、破たんする確率は99%を超えていた。
それに比べ、同じ10万の勝負回数をしても、パーレー法(5連勝でストップ)の破綻率は40%をちょっと超える程度。
負けた時の損失がせいぜい-1なので、うまく勝てない状況が続いても、耐えられるのだろう。
また、ストップをかける連勝数を5から3にすると破綻率が落ちるのは、直観的に、理解できる。
書籍の紹介
『ギャンブルの必勝法が本当に儲かるかプログラミングで検証してみた』は以下の疑問にお答えします。
●勝率が50%の場合、利益を生み出す必勝法は存在するか?
●勝率が60%の場合、どのように賭けるのが最適か?
必勝法と思われている手法を15種類紹介します。必勝法には、例えば、マーチンゲール法(負けた時に2倍賭ける手法)などがあります。これらの手法が本当に儲かるかプログラミングを使用して検証します。また、検証するために必要なプログラミングの知識(C#)も紹介しています。
ギャンブルの必勝法が本当に儲かるかプログラミングで検証してみた
関連記事
目次用の記事:ギャンブルの賭け方の種類をまとめてみた
~Webサイトを自分で作ってみませんか?~
Webサイトを運営するにはサーバーが必須です。
このサイトは、エックスサーバー のサーバーを使用しています。
エックスサーバーは無料で10日間お試しができます。
コメント