スポンサーリンク
※サイト運営にサーバーは必須です※
~このサイトもエックスサーバーを使用しています~
目次
はじめに
※目次用の記事:ギャンブルの賭け方の種類をまとめてみた
私は以前、以下の記事でマーチンゲール法のシミュレーションをしたことがある。
結果として、マーチンゲール法は継続的にお金を増やすことができないことを個人的に痛感した。
今回は以下のマーチンゲール法の変形で追検証を行いたい
- 戻り金2倍(勝率50%)→戻り金3倍(勝率33.33%)
- かけの金額を2倍→かけの金額を3倍
- 最小の賭け金を現在の自分の所持金をなんらかの形で参照する
※最小の賭けるお金を(持ち金)/512
意図
戻し金額が2倍のマーチンゲール法は、勝負回数が増えても、回収できる利益が少ない。そのため、勝負回数を2倍4倍と増やしていくといずれ、連敗の波に襲われて破綻する。
これを解消する方向性として、勝率が低いが、戻り金の割合が大きい勝負をすることが考えられる。
戻り金2倍(勝率50%)→戻り金3倍(勝率33.33%)
あるいは、
負けた時の増やす賭け金を2倍でなく3倍
にする必要がありそう
また、グランマーチンゲール法の破綻シミュレーションの記事で述べたが、マーチンゲール法は、破綻していない限り、以下のように推移することが期待される
所持金の期待値:(最初の所持金)+(勝負回数)×1/2
破綻しないための金額:(勝負回数)×2
勝負回数を重ねていくと(最初の所持金)は無視できる。いずれ、破綻しないための金額が所持金の期待値を超えてしまう。これを回避するには、何らかの形で、勝負回数が増えるにつれて、最初の所持金×(数字)みたいな形で利益を生み出さないといけない。
そのためには、最小の賭け金を現在の自分の所持金をなんらかの形で参照する必要がある
そこで、スタート時点に持っているお金を1000として、最小の賭けるお金を、ゲームで勝利した後の持ち金に512を割った数字を採用する。(数字は切り捨て)
例えば、1023なら賭ける金額のスタートは1だが、
1024になったら、賭ける金額のスタートは2(1024/512)に変わる
※このルールに従う場合9連敗しない限りゲームが続行できる。
戻り金3倍(勝率33.33%)のマーチンゲール
勝率が1/3で払戻金が3倍の勝負を基本的に想定
最小の賭け金額を自分で設定し、最初はこの最小の賭け金額からスタートする
勝った場合:次の勝負の賭け金は、設定した最小の賭け金額に戻す
負けた場合:次の勝負の賭け金は、現在賭けている2倍の金額にする
戻り金3倍(勝率33.33%)個別シミュレーション
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 |
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> int main() { int i=0; int i_max=100000;//勝負回数 double w=3.0; //賭け金の変換率(2倍以上)(win) double p=33.33; //勝率(50%以下)(probability) double m_min=1;//最小の賭け金額(money) double m_int=1000;//最初の手持ちの資金(money_initial) //乱数(時間による変化) 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_bet*2;//2倍賭け } else{//勝ちの場合 m_now =m_now+m_bet*(w-1.0); m_bet =m_min;//賭け金を最小額に戻す } 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:賭けたお金の戻る倍率を指定。ここでは3倍を指定
p:勝率を指定。ここでは1/3の確率なので33.33。
m_min:かけ金を指定
m_int:最初の資金を指定
※初期(initial)のスぺルを自分が勘違いしていたことに後から気が付いた。だが、プログラムと記事を今からすべて手直しするのはしんどいので、時間があったら、宣言する変数の名前をm=intからm_iniに書き替えたい。……文章を書いている人間の英語力の低さがばれて、地味に恥ずかしい。
※ここではm_min=1でm_int=1000と、最小の賭け金の1000倍を所持していると考えている。
例えば、最小の賭け金が1000円(千円)だとするなら、手元の軍資金は、1000000円(百万円)。割と現実的な設定だと思われる。
r:乱数(0~100の乱数)
※乱数rが勝率pより下の数で収まるなら勝ちの判定がでる。
そして、勝負を続けていくうちに、負け続けることもあるだろう。
そしてついに、賭けしようにも手持ちのお金が足りなくなるかもしれない。
この場合、これ以上勝負ができなくなり、プログラムは終了する。(破綻判定)
つまり、借金はNG
実際にプログラムを走らせると以下のような結果となる
勝負回数i_maxは100000(10万回)までとする
※ここで、表示される「賭け金」の意味は、「次の勝負に必要な賭け金」という意味で使われている。(ちょっとわかりづらいかも……)
#倍率は3.000000 勝率は33.330000 最小の賭け金は1.000000 手持ちのお金は1000.000000
1回目 賭け金は2.000000 手持ちのお金は999.000000
2回目 賭け金は4.000000 手持ちのお金は997.000000
3回目 賭け金は8.000000 手持ちのお金は993.000000
4回目 賭け金は16.000000 手持ちのお金は985.000000
5回目 賭け金は32.000000 手持ちのお金は969.000000
6回目 賭け金は64.000000 手持ちのお金は937.000000
7回目 賭け金は128.000000 手持ちのお金は873.000000
8回目 賭け金は1.000000 手持ちのお金は1129.000000
(省略)
17回目 賭け金は32.000000 手持ちのお金は1105.000000
18回目 賭け金は64.000000 手持ちのお金は1073.000000
19回目 賭け金は128.000000 手持ちのお金は1009.000000
20回目 賭け金は256.000000 手持ちのお金は881.000000
21回目 賭け金は512.000000 手持ちのお金は625.000000
22回目 賭け金は1024.000000 手持ちのお金は113.000000
22回目で手持ちのお金が足りません
※srand((unsigned)time(NULL));の部分で時間を参照した上で乱数を発生させている。
そのため、実行するタイミングで結果が変化する。
戻り金3倍(勝率33.33%)の期待値シミュレーション
上のプログラムを何度も走らせて期待値や破綻する率をもとめたい
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 |
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> int main() { int k; int k_max=100000;//試行回数 int i=0; int i_max=100000;//勝負回数 double w=3.0; //賭け金の変換率(2倍以上)(win) double p=33.33; //勝率(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; 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_bet*2;//2倍賭け } else{//勝ちの場合 m_now =m_now+m_bet*(w-1.0); m_bet =m_min;//賭け金を最小額に戻す } 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:破綻率
※ここでいう破綻率とは手持ちのお金が、2倍賭けに耐えられない状況を意味する。借金してお金を用意することはできないとする。
i_exp: 破綻するまで何回勝負ができるかの期待値
m_exp: 勝負が終わった段階で持っているお金の期待値
k_max:試行回数。
※k_maxを大きくすればするほど、正確な期待値が求まる。
以下では、k_max=100000、i_max=100000とともに10万回を指定。
勝負回数10万回、試行回数10万回。
手持ちのお金は1000でスタート(最小の賭け金額は1)
以下がプログラムを走らせた結果
勝負回数は100000
試行回数は100000
破たん回数は100000
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は232.374960
破たんする直前で持っているお金の期待値(m_exp)は973.847070
最大10万回勝負できるようなプログラムだが、破綻率が100%ということはどうやら、10万回勝負できたパターンは存在しないようだ。
勝負回数の期待値(i_exp)も232回と非常に少ない。
いわゆる普通のマーチンゲール法(勝率50%戻り金額が2倍の勝負)と比べて、i_expは10分の1以下になっている
※参考;普通のマーチンゲール法の結果は、破綻率が99.6%、勝負回数の期待値(i_exp)は3927回ほど。
賭け金3倍のマーチンゲール
勝率が1/2で払戻金が2倍の勝負を基本的に想定
最小の賭け金額を自分で設定し、最初はこの最小の賭け金額からスタートする
勝った場合:次の勝負の賭け金は、設定した最小の賭け金額に戻す
負けた場合:次の勝負の賭け金は、現在賭けている3倍の金額にする
賭け金3倍の個別シミュレーション
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 |
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> int main() { 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) //乱数(時間による変化) 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_bet*3;//3倍賭け } else{//勝ちの場合 m_now =m_now+m_bet*(w-1.0); m_bet =m_min;//賭け金を最小額に戻す } 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.000000 勝率は50.000000 最小の賭け金は1.000000 手持ちのお金は1000.000000
1回目 賭け金は3.000000 手持ちのお金は999.000000
2回目 賭け金は9.000000 手持ちのお金は996.000000
3回目 賭け金は1.000000 手持ちのお金は1005.000000
(省略)
43回目 賭け金は1.000000 手持ちのお金は1167.000000
44回目 賭け金は3.000000 手持ちのお金は1166.000000
45回目 賭け金は9.000000 手持ちのお金は1163.000000
46回目 賭け金は27.000000 手持ちのお金は1154.000000
47回目 賭け金は81.000000 手持ちのお金は1127.000000
48回目 賭け金は243.000000 手持ちのお金は1046.000000
49回目 賭け金は729.000000 手持ちのお金は803.000000
50回目 賭け金は2187.000000 手持ちのお金は74.000000
50回目で手持ちのお金が足りません
賭け金3倍の期待値シミュレーション
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 |
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> int main() { int k; int k_max=100000;//試行回数 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_intial) 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; 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_bet*3;//3倍賭け } else{//勝ちの場合 m_now =m_now+m_bet*(w-1.0); m_bet =m_min;//賭け金を最小額に戻す } 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; }//プログラムの終わり |
以下結果
勝負回数は100000
試行回数は100000
破たん回数は100000
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は258.761500
破たんする直前で持っているお金の期待値(m_exp)は989.070760
勝負回数の期待値(i_exp)は258回で、戻り金3倍(勝率33.33%)の場合は、232回だったので似たようなスピードで破たんすることがわかった。
現在の自分の所持金を最小の賭け金に反映するマーチンゲール
勝率が1/2で払戻金が2倍の勝負を基本的に想定
最小の賭け金額を(現在の持ち)/αで設定。最初は設定した最小の賭け金額からスタートする
※αに自分の好きな数字を入れていい。
勝った場合:次の勝負の賭け金は、設定した最小の賭け金額に戻す
負けた場合:次の勝負の賭け金は、現在賭けている2倍の金額にする
※以下のシミュレーションでは、最初の持ち金m_intは1000(上で紹介した2つと同じ)。α=512(2の9乗)としており、端数が出た場合は切り捨てている。
個別シミュレーション
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 |
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> int main() { 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) //乱数(時間による変化) 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=(int)m_int/512;//手持ちの資金/512でスタート 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_bet*2;//2倍賭け } else{//勝ちの場合 m_now =m_now+m_bet*(w-1.0); m_bet =(int)m_now/512;//手持ちの資金/512で再スタート } 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.000000 勝率は50.000000 最小の賭け金は1.000000 手持ちのお金は1000.000000
1回目 賭け金は1.000000 手持ちのお金は1001.000000
2回目 賭け金は2.000000 手持ちのお金は1000.000000
3回目 賭け金は4.000000 手持ちのお金は998.000000
4回目 賭け金は1.000000 手持ちのお金は1002.000000
(省略)
41回目 賭け金は4.000000 手持ちのお金は1019.000000
42回目 賭け金は1.000000 手持ちのお金は1023.000000
43回目 賭け金は2.000000 手持ちのお金は1024.000000
44回目 賭け金は4.000000 手持ちのお金は1022.000000
(省略)
141回目 賭け金は512.000000 手持ちのお金は598.000000
142回目 賭け金は1024.000000 手持ちのお金は86.000000
142回目で手持ちのお金が足りません
見ての通り、最初は、最小の賭けは、1。
(1000/512=1.95……で、切り捨てで1)
43回目で手持ちのお金は1024となり、賭け金は2でスタートするように切り替わる。
期待値シミュレーション
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 |
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> int main() { int k; int k_max=100000;//試行回数 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; double m_now;//現在の資金 double m_bet;//賭け金 //初期化 m_bet=(int)m_int/512;//手持ちの資金/512でスタート 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_bet*2;//2倍賭け } else{//勝ちの場合 m_now =m_now+m_bet*(w-1.0); m_bet =(int)m_now/512;//手持ちの資金/512で再スタート } 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; }//プログラムの終わり |
結果
勝負回数は100000
試行回数は100000
破たん回数は100000
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1025.877140
破たんする直前で持っているお金の期待値(m_exp)は270.341790
勝負回数の期待値(i_exp)が1025回。
これは、このプログラムが、最小の賭け金を(持ち金)/512をしていることから、9連敗までなんとか耐えられるが、10連敗までは耐えられないようになっている。
※正確に言えば、9連敗した場合、10回目で必要な資金が用意できない
※2の(整数)乗に近いごく一握りの数字で、ぎりぎり10回目の勝負ができる場合がある。(たぶん1023だけ)
そのため、勝負回数の期待値(i_exp)が2の10乗である1024に近い値がでるのは納得できる。
この結果の最大の特徴は、破たんする直前で持っているお金の期待値(m_exp)が270と最初に持っている1000から大幅に少なくなっている。
スタンダードな(グラン)マーチンゲールはm_exp が1000近くに収束するのに対して、大きく違うことがわかる。
端的に言えば、この賭け方は損を出すことがわかる。
なぜ、損を出すか?
連続で負けた時に、(最後に持っているお金)は、
(最後に勝利していた時に持っていたお金)-(そこから負けた分のお金)
最小のかけ金が1の場合
※持ち金が1023以下の時に10連敗することに相当
(最後に持っているお金)
(最後に勝利していた時に持っていたお金):最大で1023
(そこから負けた分のお金):511 ←(512-1)
(最後に持っているお金):せいぜい511
※(最後に持っているお金)は1023-511=512のように思えるが、512あると、もう一勝負ぎりぎり行えるので、最大はせいぜい511
最小のかけ金が2の場合
※持ち金が1535(512×3-1)以下の時に10連敗することに相当
(そこから9回負けた分のお金):1022 ←(512-1)×2
(最後に持っているお金):せいぜい513
最小のかけ金が3の場合
※持ち金が2047(512×4-1)以下の時に10連敗することに相当
(そこから9回負けた分のお金):1533 ←(512-1)×3
(最後に持っているお金):せいぜい514
調べてみるとわかるが、破綻する直前に持っているお金はおおくても512よりちょっと大きい程度。
(m_exp)は所持金の期待値なので512の半分(256)より少し多い程度が期待される。
αの値がまずかったのだろうか?
αを少し変えてみる
α=515
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1022.895450
破たんする直前で持っているお金の期待値(m_exp)は319.228930
α=530
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1055.728480
破たんする直前で持っているお金の期待値(m_exp)は499.427000
α=550
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1090.140110
破たんする直前で持っているお金の期待値(m_exp)は680.767010
α=600
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1181.201700
破たんする直前で持っているお金の期待値(m_exp)は926.878030
α=650
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1255.509420
破たんする直前で持っているお金の期待値(m_exp)は926.615660
α=700
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1337.656940
破たんする直前で持っているお金の期待値(m_exp)は992.323770
α=756(512と1024の中間)
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1440.723360
破たんする直前で持っているお金の期待値(m_exp)は1001.591430
α=800
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1509.487880
破たんする直前で持っているお金の期待値(m_exp)は987.998600
α=900
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1682.277750
破たんする直前で持っているお金の期待値(m_exp)は968.849890
α=1000
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1919.399330
破たんする直前で持っているお金の期待値(m_exp)は989.605950
これを見る限り、αの設定がまずかったのだろう。
まとめ
戻り金3倍(勝率33.33%)及び、かけの金額を3倍のマーチンゲールは、資金が枯渇するまでのスピードが速い。
最小の賭けるお金を、(持ち金)/512でスタートすると、最終的なお金の期待値はもとより低くなってしまう。持ち金の結果を反映して、最小の賭けるお金を変える場合は注意が必要。
書籍の紹介
『ギャンブルの必勝法が本当に儲かるかプログラミングで検証してみた』は以下の疑問にお答えします。
●勝率が50%の場合、利益を生み出す必勝法は存在するか?
●勝率が60%の場合、どのように賭けるのが最適か?
必勝法と思われている手法を15種類紹介します。必勝法には、例えば、マーチンゲール法(負けた時に2倍賭ける手法)などがあります。これらの手法が本当に儲かるかプログラミングを使用して検証します。また、検証するために必要なプログラミングの知識(C#)も紹介しています。
ギャンブルの必勝法が本当に儲かるかプログラミングで検証してみた
関連記事
目次用の記事:ギャンブルの賭け方の種類をまとめてみた
~プログラミングを勉強してみませんか?~
TechAcademy [テックアカデミー] は無料の体験講座が用意されているので、気軽に体験できます。
※私(サイト主)も無料体験講座を実際に受けてみました(→感想)
コメント