按概率生成随机数 .

1、生成随机数的方法 

Function SetEmpId() As String
    Dim ref As String
    Randomize
    ref = Int((99999 - 10000) * Rnd + 10000)
    SetEmpId = ref
End Function

This function’s purpose is to assign a unique five-digit number to each new employee. To generate a random integer between two given integers where ending_number = 99999 and beginning_number = 10000, the following formula is used:

= Int((ending_number - beginning_number) * Rnd + beginning_number)

2、按概率生成随机整数

以下参考:http://topic.csdn.net/t/20051018/10/4333135.html

如果要随机生成5个数,并控制它们出现的概率.

  数字     概率  
  1             10%  
  2             10%  
  3             10%  
  4             20%  
  5             50%  

那就生成0-1的随机数   
  0      --   0.1     1  
  0.1   --   0.2     2  
  0.2   --   0.3     3  
  0.3   --   0.5     4  
  0.5   --   1.0     5

3、按概率生成随机浮点数

以下来自和Tiger_Zhao讨论

如果要控制1个数落在某个区间的概率,比如要求在sngBegin和sngEnd之间生成一个随机数,这个随机数落在sngPB和sngPE之间的概率是P%。有两种方法,以第二种方法为好。

先说第一种方法,要点是:

(1)由于sngPB和sngPE将整个区间分成3部分,所以先分别计算随机数落在3部分的概率。落在sngPB和sngPE之间的概率是P%,这是已知的。余下的两个区间的总和概率是(1-p%),分到各个区间的概率按它们的长度分成。

(2)然后根据3个概率得到一个区间划分,落在第一个区间的,就在sngPB和sngPE之间生成一个随机数;落在第二个区间的,就是[sngBegin, sngPB]里生成随机数;落在第3个区间的,就在[sngPE,sngEnd]之间生数。  

'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

这个办法有个问题,就是用了两次随机数,这样实际上影响了它的随机性。Tiger_Zhao建议的第二种方法则没有这个问题,做法是:多个段有不同权重时其实可以映射成相同权重(缩放 [sngPB, sngPE] 区间,相对调整 sngEnd),这样只要一次 Rnd() 就可以完成,代码如下。

我的理解:先将区间映射为等权重区间,然后再缩放为映射之前的比例。  

'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          'PE到PB区间的长度'
    sngTLen = sngEnd - sngBegin   ‘Begin到end区间的长度,即整个区间的长度’
    
    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  ‘'PE到PB区间的长度占总区间长度的百分比’
        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

另,yesvery说,VB产生的是伪随机数,不是真正的随机数。所以,不能完全满足正态分布。

posted on 2012-06-28 12:47  很多不懂呀。。  阅读(3691)  评论(0编辑  收藏  举报

导航