数学好的进来,看看我这个按概率生成随机数的函数对不对

slowgrace 2009-03-26 10:44:56
'create a random number between sngBegin and sngEnd
'with a probability of bytP to lie within sngPB and sngPE
Public Function GetRndNumP(sngBegin As Single, sngEnd As Single, sngPB As Single, sngPE As Single, bytP As Byte) As Single
Dim bytP1 As Byte, bytP2 As Byte

Debug.Assert (sngPB >= sngBegin) And (sngPE >= sngPB) And (sngEnd >= sngPE)

'计算其他区间的概率
bytP1 = ((sngPB - sngBegin) / ((sngEnd - sngBegin) - (sngPE - sngPB))) * (100 - bytP) '[sngBegin, sngPB]
bytP2 = 100 - bytP - bytP1 '[sngPE, sngEnd]

'依据概率投射到相应区间
Select Case GetRandomNum(1, 100)
Case 1 To bytP
GetRndNumP = GetRandomNum(sngPB, sngPE)
Case (bytP + 1) To (bytP + bytP1)
GetRndNumP = GetRandomNum(sngBegin, sngPB)
Case (bytP + bytP1) + 1 To 100
GetRndNumP = GetRandomNum(sngPE, sngEnd)
End Select
End Function


Public Function GetRandomNum(sngBegin As Single, sngEnd As Single) As Single
Randomize
GetRandomNum = (sngEnd - sngBegin) * Rnd + sngBegin
End Function
...全文
769 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
z285246409 2009-03-28
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 WallesCai 的回复:]
我觉得关于VB是否能产生真正的随机数这个问题本身意义并不大.

只要在你的测试次数中它表现出随机特性,它对于你的测试来说就是真随机的.

而且我相信VB的随机数生成方法也足以支撑一般数量上的应用了.

至于一定次数内的随机数分部不均匀,那是很正常的,说明了你的测试次数还不够多.

需要注意的是, "随机数概率分布"和"在一定数量的测试次数得到的随机数分布"
这是两个概念,后者非常有可能与前者不同,甚至明显不同…
[/Quote]

学习
dufuguang 2009-03-27
  • 打赏
  • 举报
回复
看着楼上各位都脸熟!
嗷嗷叫的老马 2009-03-27
  • 打赏
  • 举报
回复
我.................看来只有路过一下了- -!
熊孩子开学喽 2009-03-27
  • 打赏
  • 举报
回复
我觉得关于VB是否能产生真正的随机数这个问题本身意义并不大.

只要在你的测试次数中它表现出随机特性,它对于你的测试来说就是真随机的.

而且我相信VB的随机数生成方法也足以支撑一般数量上的应用了.

至于一定次数内的随机数分部不均匀,那是很正常的,说明了你的测试次数还不够多.

需要注意的是, "随机数概率分布"和"在一定数量的测试次数得到的随机数分布"
这是两个概念,后者非常有可能与前者不同,甚至明显不同. 产生这种结果的原因还是因为测试次数不够造成了.

也就是说,即使有某种算法能够得到"真随机数",它依然很有可能在你有限的测试结果中呈现出一种很不均匀的分布.

这就好像是从高空中看沙漠或大海是平滑的,而身在其中的人则满眼沙丘和巨浪.

想要得到一种"均匀分布的随机数"的唯一方法,就是自己写个算法去生成这样的数列. 但是显而易见,这样的东西本身就是伪随机的.
slowgrace 2009-03-26
  • 打赏
  • 举报
回复
to zhao: 你说的是这意思吧?

'create a random number between sngBegin and sngEnd
'with a probability of bytP to lie within sngPB and sngPE
Public Function GetRndNumP(sngBegin As Single, sngEnd As Single, sngPB As Single, sngPE As Single, bytP As Byte) As Single
Dim sngPLen As Single
Dim sngTLen As Single 'total length
Dim sngIncreased As Single '需要缩放的长度
Dim sngResult As Single

sngPLen = sngPE - sngPB
sngTLen = sngEnd - sngBegin

Debug.Assert (sngPB >= sngBegin) And (sngPE >= sngPB) And (sngEnd >= sngPE)
Debug.Assert (bytP < 100) And (bytP > 0)
Debug.Assert sngTLen <> sngPLen

'映射原来的区间为等权重区间
If (sngPLen / sngTLen) * 100 = bytP Then
GetRndNumP = GetRandomNum(sngBegin, sngEnd)
Exit Function
End If

'((sngPLen + sngIncreased) / (sngTLen + sngIncreased)) * 100 = bytP
sngIncreased = ((bytP / 100) * sngTLen - sngPLen) / (1 - (bytP / 100))

'缩放回原来区间
sngResult = GetRandomNum(sngBegin, sngEnd + sngIncreased)
Select Case sngResult
Case sngBegin To sngPB
GetRndNumP = sngResult
Case sngPB To (sngPE + sngIncreased) '等比例缩放
GetRndNumP = sngPB + (sngResult - sngPB) * sngPLen / (sngPLen + sngIncreased)
Case (sngPE + sngIncreased) To sngEnd + sngIncreased '简单平移
GetRndNumP = sngResult - sngIncreased
End Select
End Function
slowgrace 2009-03-26
  • 打赏
  • 举报
回复
谢谢,你真严密!

应用的目的:要生成测试集,底层的树节点多,开始几层的树节点少。要反映这个特征。

“多个段有不同权重时其实可以映射成相同权重(缩放 [sngPB, sngPE] 区间,相对调整 sngEnd),这样只要一次 Rnd() 就可以完成。”这个主意很不错。谢谢。
Tiger_Zhao 2009-03-26
  • 打赏
  • 举报
回复
从功能上看没有大的问题,除了
1)没有处理 bytP >= 100 的情况
2)没有处理 ((sngEnd - sngBegin) - (sngPE - sngPB)) = 0 的情况
3)Randomize 只需调用一次,每次调用不仅浪费,还影响 Rnd() 的随机性。

不知道应用的目的。
多个段有不同权重时其实可以映射成相同权重(缩放 [sngPB, sngPE] 区间,相对调整 sngEnd),这样只要一次 Rnd() 就可以完成。
slowgrace 2009-03-26
  • 打赏
  • 举报
回复
补充说明如下:
(1)要求在sngBegin和sngEnd之间生成一个随机数,这个随机数落在sngPB和sngPE之间的概率是P%
(2)由于sngPB和sngPE将整个区间分成3部分,所以先分别计算随机数落在3部分的概率。落在sngPB和sngPE之间的概率是P%,这是已知的。余下的两个区间的总和概率是(1-p%),分到各个区间的概率按它们的长度分成。
(3)然后根据3个概率得到一个区间划分,落在第一个区间的,就在sngPB和sngPE之间生成一个随机数;落在第二个区间的,就是[sngBegin, sngPB]
里生成随机数;落在第3个区间的,就在[sngPE,sngEnd]之间生数。

这里实际上用了两次随机数。第一次是保证概率,第二次是随机。但不知道为啥觉得这样好像不够随机的说……

数学好的帮判判?
slowgrace 2009-03-26
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 clear_zero 的回复:]
:)
[/Quote]

谢谢哦。那边的帖子你也回一下啊,我好给你分呀。
slowgrace 2009-03-26
  • 打赏
  • 举报
回复
感谢zhao和yesvery指点,我把这个帖子的讨论总结在这里:http://blog.csdn.net/slowgrace/archive/2009/03/25/4022632.aspx
clear_zero 2009-03-26
  • 打赏
  • 举报
回复
:)
slowgrace 2009-03-26
  • 打赏
  • 举报
回复
节点数有30%的概率落在20到100之间。
slowgrace 2009-03-26
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 Tiger_Zhao 的回复:]
就是这个意思。

不知道你这个随机数如何映射成节点,要控制数量的多少,直接用节点所在层数决定一个数量不是更简单?
[/Quote]

是这么用:

       '层次越深 节点越多,基础节点也越多
Select Case bytCurLevel
Case 1
bytNodeCount = GetRandomNum(5, 15)
bytPBasic = 33
Case 2
bytNodeCount = GetRandomNum(1, 20)
bytPBasic = 33
Case Is >= 3
bytNodeCount = GetRndNumP(1, 100, 20, 100, bytCurLevel * 10)
bytPBasic = IIf(((bytCurLevel * 10) + 50) > 99, 99, ((bytCurLevel * 10) + 50))
End Select
slowgrace 2009-03-26
  • 打赏
  • 举报
回复
谢谢提醒
Tiger_Zhao 2009-03-26
  • 打赏
  • 举报
回复
就是这个意思。

不知道你这个随机数如何映射成节点,要控制数量的多少,直接用节点所在层数决定一个数量不是更简单?
yesvery 2009-03-26
  • 打赏
  • 举报
回复
应该注意的是:VB产生的是伪随机数,不是真正的随机数。
所以,不能完全满足正态分布
白发程序猿 2009-03-26
  • 打赏
  • 举报
回复
来学习的,代码能基本看懂,但不明白为什么
此源码为基础底层代码贴,没有应用代码。是作为运行库使用的。 一:易原生随机数特性 易语言生成随机数,其实为平均分布的随机数。 即是为多个随机数是满足平均分布规律的,也就是说所有范围内的数都是一样多的。 下图为100万个易随机数的,概率分布图。 二、随机数的应用 由上可以看出,虽然规律很好。但这样的分布规律并不能满足我们所有的需求。 我们需要在某些时候让一些区域分布减少或都加。平均随机数就不能满足我们需求了。 比如, 1、发牌时,可以让一些牌发放机率高,一些牌机率低。 2、验证码生成时,可以让一些因素生成高,一些低。 3、抽奖时,可以让一些数字高,一些数据字,甚至是没有。 (虽然看起来数据都是随机杂乱的,但是经过概率设定,可以是完全没有),这样一想大多数的抽奖软件,背后操作空间真是太大了。 4、所有需用随机数的地方都可以用到。 三、统计学常用的随机分布 以下只贴几个数学上常用的随机数的分布图形。这些都只需作为了解 四、任意分布随机数 这里说的是本文的重点。 本模块源码重点包含两块算法: 1、正态随机数的算法生成(多次单个随机数生成) 单个点生成点的概率按正态分布,无数个后统计规律呈现正态分布特性。 基于Box–Muller变换的正态随机数生成方法 2、任意分布随机数的类(一次多个随机数生成) 任意随机数的生成算法,这里就不详讲,算法是我自创。各位不用非得理解里面的算法。 这算法没有数字理论证明,在数学应用上是不存在"任意分布随机数"的算法的。 也不存在统一的数学算法,那是因为绝大多数的概率密度函数是不可计算反函数。 而要正面生成概率随机数,就必须得到概率分布函数的反函数。这就是几乎不可能做到的事。 (这一点可以在正态分布随机数源码中看得到) 我使用的算法是我自创的,算法并不复杂,但算法很抽象。重在于快速、稳定、可靠。(源码各位能理解就理解,理解不了,直接调用就行) 实际无数次使用完全符合理论分布规律,各位可以随意点击尝试分布曲线,是否是按预设的一样。

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧