【问题标题】:VBA Random Number in Simulation模拟中的 VBA 随机数
【发布时间】:2017-07-06 21:42:38
【问题描述】:

我正在尝试创建一个棒球季后赛模拟器,以了解一个糟糕的投手对球队的冠军几率有多大影响。所以我基本上为季后赛创建了一个模拟器(3轮,第一轮是最好的5轮,接下来的两轮是最好的7轮)。而且我可以看到如果一个SP每三场比赛投球一次,他会减少10%的获胜机会,会对球队造成多大的伤害。

为了确保我写了这篇文章,我首先在没有任何调整的情况下运行了我的模拟,所以每场比赛两支球队都有 50% 的机会获胜......(因此一支球队有 12.5% 的机会赢得世界大赛在 3 轮季后赛中)但是,我的得分一直高于 12.5。

我感觉问题出在 Rnd 函数上,所以我玩了一下(添加了一个函数,尝试改变时间等),现在我的模拟结果为

我做错了什么,或者这只是 rnd 函数不擅长处理的事情?

Public Function wRandomNumber(lowerbound, upperbound, Optional rndType = 1) As Double
Dim rndVariable As Double
'Const ms As Double = 0.000000011574

Randomize Timer
'Application.Wait Now + ms * 1
rndVariable = Rnd
If rndType = 1 Then
    wRandomNumber = Int((upperbound - lowerbound + 1) * rndVariable + lowerbound)
ElseIf rndType = 2 Then
    If (upperbound - lowerbound + 1) * rndVariable + lowerbound <= upperbound Then
        wRandomNumber = (upperbound - lowerbound + 1) * rndVariable + lowerbound
    Else
        Do While (upperbound - lowerbound + 1) * rndVariable + lowerbound > upperbound
            rndVariable = Rnd
            If (upperbound - lowerbound + 1) * rndVariable + lowerbound <= upperbound Then
                wRandomNumber = (upperbound - lowerbound + 1) * rndVariable + lowerbound
            End If
        Loop
    End If
End If
End Function

Public Sub Playoff_sim()

Dim game_num As Integer
Dim lds_wins_stros As Integer
Dim lds_loss_stros As Integer
Dim lcs_wins_stros As Integer
Dim lcs_loss_stros As Integer
Dim ws_wins_stros As Integer
Dim ws_loss_stros As Integer
Dim p As Double
Dim outcome1 As Single
Dim outcome2 As Single
Dim outcome3 As Single
Dim i As Double
Dim iter As Double
Dim CHAMPS As Double
Dim Loser As Double
Dim p_bad As Double
Dim p_norm As Double
Dim lds_champs As Double
Dim lcs_champs As Double
Dim r As Double
Const ms As Double = 0.000000011574

iter = 100000
CHAMPS = 0
Loser = 0
lds_champs = 0
lcs_champs = 0
p_bad = 0.5
p_norm = 0.5
r = 0
For i = 1 To iter

game_num = 1
lds_wins_stros = 0
lds_loss_stros = 0
lcs_wins_stros = 0
lcs_loss_stros = 0
ws_loss_stros = 0
ws_wins_stros = 0

Do Until lds_wins_stros = 3 Or lds_loss_stros = 3

outcome1 = wRandomNumber(0, 1, 2)
    If game_num = 3 Then
        p = p_bad
    Else
        p = p_norm
    End If

    If p > outcome1 Then
        lds_wins_stros = lds_wins_stros + 1
    Else
        lds_loss_stros = lds_loss_stros + 1
    End If
    r = r + 1
    'Worksheets("Playoff_Sim").Cells(r, 15).Value = outcome1

game_num = game_num + 1
Loop

If lds_wins_stros = 3 Then

    outcome2 = wRandomNumber(0, 1, 2)
    lds_champs = 1 + lds_champs
    Do Until lcs_wins_stros = 4 Or lcs_loss_stros = 4

    If game_num = 3 Or 6 Or 9 Or 12 Or 15 Or 18 Or 21 Then
        p = p_bad
    Else
        p = p_norm
    End If

    If p > outcome2 Then
        lcs_wins_stros = lcs_wins_stros + 1
    Else
        lcs_loss_stros = lcs_loss_stros + 1
    End If

    game_num = game_num + 1

    Loop

    If lcs_wins_stros = 4 Then
        lcs_champs = lcs_champs + 1

        outcome3 = wRandomNumber(0, 1, 2)
        Do Until ws_wins_stros = 4 Or ws_loss_stros = 4

            If game_num = 3 Or 6 Or 9 Or 12 Or 15 Or 18 Or 21 Then
                p = p_bad
            Else
                p = p_norm
            End If

            If p > outcome3 Then
                ws_wins_stros = ws_wins_stros + 1
            Else
                ws_loss_stros = ws_loss_stros + 1
            End If
        'r = r + 1
        game_num = game_num + 1
        'Worksheets("Playoff_Sim").Cells(r, 15).Value = outcome3
        Loop

        If ws_wins_stros = 4 Then
            CHAMPS = CHAMPS + 1
        Else
            Loser = Loser + 1
        End If

    Else
        Loser = Loser + 1
    End If

Else
    Loser = Loser + 1
End If

Next i

Worksheets("Playoff_Sim").Cells(2, 1).Value = CHAMPS
Worksheets("Playoff_Sim").Cells(2, 2).Value = Loser
Worksheets("Playoff_Sim").Cells(2, 3).Value = lds_champs
Worksheets("Playoff_Sim").Cells(2, 4).Value = lcs_champs

结束子

【问题讨论】:

  • If (upperbound - lowerbound + 1) * rndVariable + lowerbound &lt;= upperbound你想通过这个检查来达到什么目的??
  • 请注意,您可以使用Application.RandBetween(0,1) 让生活更轻松。它非常接近 50/50%,精度为 1/1000,因此您不必担心。
  • 我从另一个线程复制了 wRandomNumber 用户函数来测试,看看我创建随机数的方式是否是问题所在。所以我实际上并不完全确定那条线的目的是什么。我绝对不需要使用用户函数,因为我可以将我的“结果”变量 = 设置为 Rnd(在随机化之后)。
  • Application.RandBetween 给了我很好的结果。谢谢!

标签: vba random simulator


【解决方案1】:

问题不仅在于随机数(可以通过@A.S.H 的建议使用Application.RandBetween 来解决),还在于您的模拟逻辑。重复两次的代码片段

If game_num = 3 Or 6 Or 9 Or 12 Or 15 Or 18 Or 21 Then
    p = p_bad
Else
    p = p_norm
End If

相当于单行p = p_bad。这是因为条件 game_num = 3 Or 6 Or 9 Or 12 Or 15 Or 18 Or 21 始终计算为 True,因为您只是将 game_num3 进行比较,然后强制 VBA 将剩余数字(6、9、15、18、21)解释为 True通过与他们一起使用Or 运算符。相反,只需这样做:

If game_num Mod 3 = 0 Then
    p = p_bad
Else
    p = p_norm
End If

可能还有其他问题,尽管这应该足以让您开始。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-05
    • 2015-04-23
    • 2013-04-13
    • 2021-06-26
    相关资源
    最近更新 更多