按概率生成随机数

版权声明:可以任意转载,转载时请务必以超链接形式标明如下文章原始出处和作者信息及本声明

作者:xixi

出处:http://blog.csdn.net/slowgrace/archive/2009/03/25/4022632.aspx

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
    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

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

你可能感兴趣的:(function,String,Integer,Random,vb,byte)