欢迎光临散文网 会员登陆 & 注册

用excel VBA模拟醉汉走路过程

2023-06-10 11:51 作者:小给猫  | 我要投稿

李永乐老师曾经讲过一个“醉汉走路”问题。这个问题常被用来解释布朗运动※。说一个醉汉,已经意识模糊,但任然可以走路。只不过,他走路的方向是完全随机的。那么经过一定的步数以后,醉汉是倾向于原地打转,还是离开起点一定距离呢?

※布朗运动指的是极小的微粒(比如一粒花粉),受到周围众多处于无序热运动中的粒子(比如分子)扰动,“被迫”进行无序的运动

 

答案是,醉汉倾向于离开起点一定距离,而不是原地打转。具体的请大家移步李永乐老师的频道。在这里,我只想介绍一种用excel及其附带的VBA工具,来模拟“醉汉走路”过程的方法。

首先,舞台在excel的表格上。也就是说,最小的单元就是一个单元格。每一次移动就是随机地移动到相邻的8个单元格中的其中1个(移动到斜对角也算1格)。限定的步数为100步。所以,为了有足够大的空间,把起始位置设定到坐标为(101,101)※的单元格上,把它用黄色边框标记。这样即使出现始终往一个方向运动的情况也不会超出范围。

※VBA里描述单元格坐标的格式为(行序号,列序号)。如第3行,B列就是(3,2)

然后,每到达一个单元格,就让其中显示数字,记录到达过的次数※。同时也为这些单元格上色,到达次数越多颜色就越深。最后给终点标记上红色。

※起点在一开始时不会被计数,但之后会正常计数。所以起点格中的数字代表返回起点的次数

上图显示了1次运行的结果。可以看出,这次运动没有返回过起点,在上方的一片区域(数字为4,5,6)盘旋了多次,最后位置在右下方的一个曾经到达过的位置。因为是随机※的运动,每一次运行的结果会不一样。当然,步数也可以被设置为更大的值,只不过要将起点设置得远一些以获得更大的舞台。下面是代码。

※像VBA这样弱小的编程工具里是不存在真随机的,这里只是简单模拟

Sub walk2()

 Dim x As Integer

 Dim y As Integer

 Dim i As Integer

 Dim temp As Double

 

 Range(Cells(1, 1), Cells(200, 200)).Interior.Pattern = xlNone

 Range(Cells(1, 1), Cells(200, 200)).ClearContents

 ‘清除范围内的底色和数值

 x = 101

 y = 101

‘设置起点坐标。这里y代表行,x代表列

 For i = 1 To 100

  temp = 8 * Rnd

  If temp < 1 Then

   y = y - 1

   ElseIf temp >= 1 And temp < 2 Then

   x = x + 1

   y = y - 1

   ElseIf temp >= 2 And temp < 3 Then

   x = x + 1

   ElseIf temp >= 3 And temp < 4 Then

   x = x + 1

   y = y + 1

   ElseIf temp >= 4 And temp < 5 Then

   y = y + 1

   ElseIf temp >= 5 And temp < 6 Then

   x = x - 1

   y = y + 1

   ElseIf temp >= 6 And temp < 7 Then

   x = x - 1

   ElseIf temp >= 7 And temp <= 8 Then

   x = x - 1

   y = y - 1

  End If

 ‘获取1个0~8的随机数,根据数值决定下一格的位置。重复100次

  Cells(y, x).Value = Cells(y, x).Value + 1

 ‘给到达过的格子计数

  Cells(y, x).Interior.Color = RGB(255 - 17 * Cells(y, x).Value, 255 - 17 * Cells(y, x).Value, 255 - 17 * Cells(y, x).Value)

‘给到达过的格子上色

 Next i

 Cells(y, x).Interior.Color = RGB(255, 0, 0)

‘给终点格上红色

 

End Sub

 

当然,这个运行过程相当快。如果想要看到过程的话,需要在每一步之间加入延时。VBA并没有自带的延时,需要自己写一个。方法有很多,我提供一个以获取系统时间的方式实现的代码。可以实现1秒的延时。

Sub delay1000()

 Dim t1 As Single

 

 t1 = Timer

 Do

  DoEvents

 Loop While Timer - t1 < 1

 

End Sub

 

用“call delay1000”这个语句调用延时,加在之前的“Next i”的上一句就行了。

然后,为了可视化效果更好一点,在加数字和上色的同时,还可以令单元格被选中。用“cells(y,x).select”这个语句。

运行的效果我已经录成视频了。

 

最后,我想用这种方式来计算运动100步后,终点与起点距离的数学期望的近似值※。只不过,因为前面把移动到斜对角也看作1步了,所以计算距离的方法需要做些改变,以最小的格子数来表示。

※也就是多次运行结果的平均值。运行次数越多就越逼近数学期望

如果初始坐标是(a,b),终点坐标是(x,y)。那么距离就是:

Max(Abs(a-x),Abs(b-y))

比如下面这个例子,行方向上相距3,列方向上相距7,所以距离就是较大的7 。

因为不需要显示出来,所以可以略去部分代码。再加上一层循环,以及计算最终结果部分。代码如下。

Sub walk5()

 Dim x As Integer

 Dim y As Integer

 Dim i As Integer

 Dim j As Integer

 Dim temp As Double

 Dim d As Double

 

 For j = 1 To 10000

  x = 101

  y = 101

  For i = 1 To 100

   temp = 8 * Rnd

   If temp < 1 Then

    y = y - 1

    ElseIf temp >= 1 And temp < 2 Then

    x = x + 1

    y = y - 1

    ElseIf temp >= 2 And temp < 3 Then

    x = x + 1

    ElseIf temp >= 3 And temp < 4 Then

    x = x + 1

    y = y + 1

    ElseIf temp >= 4 And temp < 5 Then

    y = y + 1

    ElseIf temp >= 5 And temp < 6 Then

    x = x - 1

    y = y + 1

    ElseIf temp >= 6 And temp < 7 Then

    x = x - 1

    ElseIf temp >= 7 And temp <= 8 Then

    x = x - 1

    y = y - 1

   End If

  Next i

  If Abs(x - 101) >= Abs(y - 101) Then

   d = d + Abs(x - 101) / 10000

   Else

   d = d + Abs(y - 101) / 10000

  End If

 Next j

 MsgBox d

 

End Sub

 

我运行了几次,基本上是在9.7~9.8之间。与布朗运动的规律是接近的。布朗运动的期望是步数的平方根。运动100步,距离的期望就是10步。运动10000步,距离的期望就是100步。你也可以copy这个代码,将步数(i的值)修改成10000,看看结果会不会是100附近(运行起来可能有点费时)。


用excel VBA模拟醉汉走路过程的评论 (共 条)

分享到微博请遵守国家法律