スポンサーリンク
※サイト運営にサーバーは必須です※
~ ロリポップ! はコスパのよい初心者向けサーバーです~
目次
はじめに
※目次用の記事:ギャンブルの賭け方の種類をまとめてみた
賭け方の一つに10%投資法という手法が存在する。
賭け方はいたって簡単で手持ちのお金の10%を賭ければよい。
勝っている場合は、賭ける金額が増え、負け越している場合は、賭ける金額が減少する。
たとえ、負け続けていた場合でも、お金の減少が緩やかで、連敗が続いても耐えられる賭け方だと紹介されることが多い。
しかし、本当だろうか?
この記事では、c++/c言語でのシミュレーション結果を紹介する。
また、なぜ10%は儲からないか説明する。
10%投資法とは
自分の手持ちのお金の10%を賭ける
例えば、
手持ちのお金:100円→賭ける金:10円
手持ちのお金:320円→賭ける金:32円
最後の桁を、「切り捨て」にするか、「切り上げ」にするか、「四捨五入」にするかはお好みで変更。
※以下のプログラムのシミュレーションは、「切り捨て」を採用している。
プログラミングをしたことがある人は何となくわかると思うが、「切り上げ」や「四捨五入」は、「切り捨て」と比べるとひと手間加えないといけないため。
単純な問題
10%投資法の説明に入る前に、ここで一つ問題。
Question:
原価1000円の商品を売っていました。
利益を出すために、1割高い値段を売値にしました。
ところが、お客が来なかったので売値より1割安い値段で売りました。
さて、商品の値段は何円でしょうか?(小学生レベルの問題)
Answer:
答えは1000円ではない。
正しい答えは990円だ
理由:1000×1.1×0.9=990円
10%投資法の具体例
手持ちの金を100でスタートして、2回勝負した時の表は以下のようになる
勝負 | 1回目 | 2回目 | 利益 |
○○ | 110 | 121 | 21 |
○× | 110 | 99 | -1 |
×○ | 90 | 99 | -1 |
×× | 90 | 81 | -19 |
期待値 | 0 |
負け続けた時の損は-19に対して、勝ちつづけた時の利益は+21と大きい。
表からわかるように勝ち負けの数が同じ時は99となり、-1だけ損する。
これは何を意味するか?
- 勝ち続けた時の利益がでかい
- 負け続けた時の損失は緩やか
- 勝ちと負けの数が同じぐらいだと結局、損する
つまり、負け続けた時の損失が緩和されている分、勝ちと負けの数が同じぐらいのところで皺寄せされている、と解釈することができる
※参考までに4回まで勝負した時のテーブルを乗せておく
勝負 | 1 | 2 | 3 | 4 |
○○○○ | 11000 | 12100 | 13310 | 14641 |
○○○× | 11000 | 12100 | 13310 | 11979 |
○○×○ | 11000 | 12100 | 10890 | 11979 |
○○×× | 11000 | 12100 | 10890 | 9801 |
○×○○ | 11000 | 9900 | 10890 | 11979 |
○×○× | 11000 | 9900 | 10890 | 9801 |
○××○ | 11000 | 9900 | 8910 | 9801 |
○××× | 11000 | 9900 | 8910 | 8019 |
×○○○ | 9000 | 9900 | 10890 | 11979 |
×○○× | 9000 | 9900 | 10890 | 9801 |
×○×○ | 9000 | 9900 | 8910 | 9801 |
×○×× | 9000 | 9900 | 8910 | 8019 |
××○○ | 9000 | 8100 | 8910 | 9801 |
××○× | 9000 | 8100 | 8910 | 8019 |
×××○ | 9000 | 8100 | 7290 | 8019 |
×××× | 9000 | 8100 | 7290 | 6561 |
期待値 | 10000 | 10000 | 10000 | 10000 |
10%投資法の検証
以下では2つのプログラムを紹介する。
言語はC++で作ったが、C言語としてコンパイルしても動くと思う
※このプログラムを組んだ人間は、大学時代に少しプログラムをかじった程度の戦闘能力しかない
10%投資法個別シミュレーション
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 |
#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) int c;//勝ち負け差のカウント(count) c=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); double m_now;//現在の資金 double m_bet;//賭け金 //初期化 m_now=m_int;//最初は最初の手持ちの資金でスタート m_bet=int(m_now/10);//賭け金は資金の1/10でスタート for(i=1;i<=i_max;i++) { double r;//乱数(rand) r=100.0*rand()/(RAND_MAX+1.0);//0から100の乱数を出す printf("%d回目\t賭け金は%lf\t",i,m_bet); fprintf(sf,"%d回目\t賭け金は%lf\t",i,m_bet); if (p<=r){//負けの場合 m_now-=m_bet; c-=1; printf("lose\t"); fprintf(sf,"lose\t"); } else{//勝ちの場合 m_now +=m_bet*(w-1.0); c+=1; printf("win\t"); fprintf(sf,"win\t"); } m_bet=int(m_now/10);//賭け金を手持ちの1/10にする printf("勝負差%d\t手持ちのお金は%lf\n",c,m_now); fprintf(sf,"勝負差%d\t手持ちのお金は%lf\n",c,m_now); if(m_bet==0){//手持ちの金の1/10で切り捨てした時、0になってしまう場合 printf("%d回目賭け金が0になります\n",i); fprintf(sf,"%d回目賭け金が0になります\n",i); break; } 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:勝率を指定。ここでは1/2の確率なので50。
m_min:かけ金を指定
m_int:最初の資金を指定
※初期(initial)のスぺルを自分が勘違いしていたことに後から気が付いた。だが、プログラムと記事を今からすべて手直しするのはしんどいので、時間があったら、宣言する変数の名前をm=intからm_iniに書き替えたい。……文章を書いている人間の英語力の低さがばれて、地味に恥ずかしい。
※ここではm_min=1でm_int=1000と、最小の賭け金の1000倍を所持していると考えている。
例えば、最小の賭け金が1000円(千円)だとするなら、手元の軍資金は、1000000円(百万円)。割と現実的な設定だと思われる。
r:乱数(0~100の乱数)
※乱数rが勝率pより下の数で収まるなら勝ちの判定がでる。
そして、勝負を続けていくうちに、負け続けることもあるだろう。
そしてついに、賭けしようにも手持ちのお金が足りなくなるかもしれない。
この場合、これ以上勝負ができなくなり、プログラムは終了する。(破綻判定)
つまり、借金はNG
※マーチンゲール法になかった変数
c:トータルの勝ち負けの差がどのくらいあるか調べる用 。
10回勝負して6勝4負けなら+2 ←(+6−4)
10回勝負して3勝7負けなら−4 ←(+3−7)
実際にプログラムを走らせると以下のような結果となる
勝負回数i_maxは100000(10万回)までとする
#倍率は2.000000 勝率は50.000000 最小の賭け金は1.000000 手持ちのお金は1000.000000
1回目 賭け金は100.000000 lose 勝負差-1 手持ちのお金は900.000000
2回目 賭け金は90.000000 win 勝負差0 手持ちのお金は990.000000
3回目 賭け金は99.000000 lose 勝負差-1 手持ちのお金は891.000000
(省略)
810回目 賭け金は1.000000 lose 勝負差-8 手持ちのお金は10.000000
811回目 賭け金は1.000000 lose 勝負差-9 手持ちのお金は9.000000
811回目賭け金が0になります
手持ちのお金を1/10にして切り捨てているため、手持ちのお金が10を下回ると、切り捨てた時のお金が0になり、賭けの続行ができないと判定がでるようになっている。
※もしも、手持ちのお金がゼロになるまで賭けを続けるプログラムにしたいのなら、m_bet=max(m_int/10,m_min)みたいに宣言して、手持ちお金の1/10(m_int/10)が0になった時、最小の賭け金額(m_min:1)が採用されるようにする
※srand((unsigned)time(NULL));の部分で時間を参照した上で乱数を発生させている。そのため、実行するタイミングで結果が変化する。
10%投資法の期待値シミュレーション
上のプログラムを何度も走らせて期待値や破綻する率をもとめたい
そのためのプログラムは以下のようになる
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 150 151 152 153 154 155 |
#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; int c_sum;//勝負差の合計 c_sum=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_now=m_int;//最初は最初の手持ちの資金でスタート m_bet=int(m_now/10);//賭け金は資金の1/10でスタート int c;//勝ち負け差のカウント(count) c=0;//初期化 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_bet; c-=1; } else{//勝ちの場合 m_now +=m_bet*(w-1.0); c+=1; } m_bet=int(m_now/10);//賭け金を手持ちの1/10にする i_cout=i;//i_coutを定義しないと破たんしない(セーフ)場合、iと値が1ずれてしまうため if(m_bet==0){//手持ちの金の1/10で切り捨てした時、0になってしまう場合 break; } 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; c_sum=c_sum+c; }//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); double c_exp=(double)c_sum/(double)k_max; printf("破たんした時の勝負差の期待値は%lf\n",c_exp); fprintf(sf,"破たんした時の勝負差の期待値は%lf\n",c_exp); //sfクローズ fclose(sf); return 0; }//プログラムの終わり |
プログラムで使用している変数の説明
b_pro:破綻率
※ここでいう破綻率とは手持ちのお金が、賭けに耐えられない状況を意味する。借金してお金を用意することはできないとする。
i_exp: 破綻するまで何回勝負ができるかの期待値
m_exp: 勝負が終わった段階で持っているお金の期待値
k_max:試行回数。
※k_maxを大きくすればするほど、正確な期待値が求まる。
※マーチンゲール法になかった要素
c_exp:勝敗差の期待値
以下では、k_max=100000、i_max=100000で指定。
試行回数10万回、勝負回数10万回。
手持ちのお金は1000でスタート
#倍率は2.000000 勝率は50.000000 最小の賭け金は1.000000 手持ちのお金は1000.000000
1番目343回目で破たん 手持ちのお金は9.000000
(省略)
100000番目733回目で破たん 手持ちのお金は9.000000
勝負回数は100000
試行回数は100000
破たん回数は100000
破たん率は100.000000%
破たんするまでに行える勝負回数の期待値(i_exp)は1070.484100
破たんする直前で持っているお金の期待値(m_exp)は9.000000
破たんした時の勝負差の期待値は0.041100
10万回勝負したら、必ず100%で破綻していることがわかる。
破たんする直前で持っているお金の期待値が9なのは、上のプログラムでも説明したが、持ち金が10を下回ると、10%して切る捨てた時のかけ金が0になり、勝負ができないと判定されるから
破たんするまでに行える勝負回数の期待値は1070回。
破たんした時の勝負差の期待値は0.04でほぼ0で、勝ちと負けの回数がほぼ同じ。
これが意味するのは「負け越して、破綻したというわけではない」ということ。
期待値という観点で、ざっくり考えると、破綻した時におよそ1070回で、勝ちが535回で負けが535回程度している
※正確には、上の文章は正しくない。平均1070回の勝負をしているが、1070回よりも早い段階で負けた場合は、ある程度負け越してゲームが終了する事象が多いだろう。一方で、1070回よりも長く勝負できている場合は、勝負回数的には勝ち越していている事象が多いと考えられる。平均して1070回目で破たんしており、平均して勝負差が0だからといって、1070回付近で破たんする事象において、勝敗の差が均等という保証はない。
ちなみに、破たん率は100%で、勝負回数の期待値が1070回というのは、個人的にかなり破綻するまでのスピードはかなり速いと思う。
破綻(パンク)するまでのスピードが速いとされているマーチンゲール法ですら、破綻率は99%後半で100%には届かなかった。勝負回数の期待値も3000回は超えていた。
結果考察
勝負をして勝ち負けが同じ程度だと、×0.99されていき、最終的にお金をすり減らす。
最初1000あったお金も、最後には10を下回り、勝負ができなくなる。
ここで、0.99を何乗すると0.01(10/1000)になるか考えてみる
乗数 | 値 |
1 | 0.99 |
2 | 0.9801 |
10 | 0.904382 |
50 | 0.605006 |
100 | 0.366032 |
200 | 0.13398 |
300 | 0.049041 |
400 | 0.017951 |
458 | 0.010021 |
459 | 0.009921 |
500 | 0.00657 |
535 | 0.004622 |
0.99を458.2乗すると0.01になる
※458.2という値は、エクセルなどでで0.99を底にして値(ここでは0.01)を入れると見積もれる(=LOG(0.01,0.99))
※今回の場合、正確には、0.01(10/1000)でなく0.009(9/1000)になるポイントを考えるべき
※0.99の535(1070/2)乗の値が0.00462で2倍にすると約0.009。2倍のファクターがどこからやってくるかいまいちよくわからない……
まとめ
以上のことからもわかる通り、10%投資法は、必勝法ならぬ、必負法といえる。
では、どうすれば、よいか?
私は、最初の方で、「負け続けた時の損失が緩和されている分、勝ちと負けの数が同じぐらいのところで皺寄せされている」と述べた。
原因は勝敗の回数が同じ程度でも損してしまうことだ。
そのため、なにかしらの形で、勝ちと負けの数が同じぐらいのところで損ではなく利益がでるような賭け方を考えれば、必勝法になりうるのかもしれない……
書籍の紹介
『ギャンブルの必勝法が本当に儲かるかプログラミングで検証してみた』は以下の疑問にお答えします。
●勝率が50%の場合、利益を生み出す必勝法は存在するか?
●勝率が60%の場合、どのように賭けるのが最適か?
必勝法と思われている手法を15種類紹介します。必勝法には、例えば、マーチンゲール法(負けた時に2倍賭ける手法)などがあります。これらの手法が本当に儲かるかプログラミングを使用して検証します。また、検証するために必要なプログラミングの知識(C#)も紹介しています。
ギャンブルの必勝法が本当に儲かるかプログラミングで検証してみた
関連記事
※目次用の記事:ギャンブルの賭け方の種類をまとめてみた
~ギャンブルに絶対儲かる必勝法があるのだろうか?~
私(サイト主)はこの疑問に対して非常に興味を持ち、プログラミングで検証してみました。
このサイトを応援してもいいかなと思う人はぜひとも購入を検討してみてください。
コメント