Excel UDF加权RANDBETWEEN()

Gre*_*edo 12 excel vba excel-vba user-defined-functions

好吧不是真的RANDBETWEEN().我正在尝试创建一个UDF来返回数组中数字的索引,其中数字越大,选择的可能性就越大.

我知道如何将概率分配给工作表中的随机数(即使用MATCH()概率的总和,SO上有很多东西来解释),但我想要一个UDF,因为我将一个特殊的输入数组传递给函数 -不仅仅是一个选定的范围.

我的问题是,加权是关闭的,数组中的数字后面的数字比数组中的数字更有可能被返回,我无法看到我的代码中哪里出错了.到目前为止这是UDF:

Public Function PROBABLE(ParamArray inputArray() As Variant) As Long
'Takes a set of relative or absolute probabilities and ranks a random number within them
Application.Volatile (True)
Dim outputArray() As Variant
Dim scalar As Single
Dim rankNum As Single
Dim runningTot As Single

'''''
'Here I take inputArray() and convert to outputArray(), 
'which is fed into the probability code below
'''''

scalar = 1 / WorksheetFunction.Sum(outputArray)
rankNum = Rnd()
runningTot = 0

For i = 0 To UBound(outputArray)
    runningTot = runningTot + outputArray(i)
    If runningTot * scalar >= rankNum Then
        PROBABLE = i + 1
        Exit Function
    End If
Next i

End Function
Run Code Online (Sandbox Code Playgroud)

该函数应该查看数字的相对大小outputArray()并随机选择,但是对较大的数字加权.例如outputArray(){1,0,0,1}应分别分配概率{50%,0%,0%,50%}然而,当我测试的outputArray(),对于1000个样本和100次迭代,并作图项1或阵列中的第4项是如何经常被退回,我得到这个结果:图形

大约20%:80%的分布.绘图{1,1,1,1}(所有应该有相同的机会)给出了10%:20%:30%:40%的分布

我知道我错过了一些明显的东西,但我不知道是什么,有什么帮助吗?

UPDATE

有些人要求提供完整的代码,就在这里.

Public Function PROBABLE(ParamArray inputArray() As Variant) As Long
'Takes a set of relative or absolute probabilities and ranks a random number within them
Application.Volatile (True) 'added some dimensions up here
Dim outputArray() As Variant
Dim inElement As Variant
Dim subcell As Variant
Dim scalar As Single
Dim rankNum As Single
Dim runningTot As Single
'convert ranges to values
'creating a new array from the mixture of ranges and values in the input array
''''
'This is where I create outputArray() from inputArray()
''''
ReDim outputArray(0)
For Each inElement In inputArray
'Normal values get copied from the input UDF to an output array, ranges get split up then appended
    If TypeName(inElement) = "Range" Or TypeName(inElement) = "Variant()" Then
        For Each subcell In inElement
            outputArray(UBound(outputArray)) = subcell
            ReDim Preserve outputArray(UBound(outputArray) + 1)
        Next subcell
    'Stick the element on the end of an output array
    Else
        outputArray(UBound(outputArray)) = inElement
        ReDim Preserve outputArray(UBound(outputArray) + 1)
    End If
Next inElement
ReDim Preserve outputArray(UBound(outputArray) - 1)
''''
'End of new code, the rest is as before
''''
scalar = 1 / WorksheetFunction.Sum(outputArray)
rankNum = Rnd()
runningTot = 0

For i = 0 To UBound(outputArray)
    runningTot = runningTot + outputArray(i)
    If runningTot * scalar >= rankNum Then
        PROBABLE = i + 1
        Exit Function
    End If
Next i

End Function
Run Code Online (Sandbox Code Playgroud)

start inputArray() outputArray()部分用于标准化不同的输入方法.即,用户可以输入值,单元格引用/范围和数组的混合,并且该功能可以应对.例如{=PROBABLE(A1,5,B1:C15,IF(ISTEXT(D1:D3),LEN(D1:D3),0))} (你得到的图片)应该像以前一样工作=PROBABLE(A1:A3).我循环遍历inputArray()的子元素并将它们放在我的outputArray()中.我相当确定这段代码没什么问题.

然后为了得到我的结果,我将UDF复制到A1:A1000,使用COUNTIF(A1:A1000,1)或代替计数1,我为每个可能的UDF输出计数2,3,4等,并做了一个短宏来重新计算表单100次,每次将countif的结果复制到表格中.我不能确切地说我是怎么做到的,因为我把这一切都留在了工作中,但我会在星期一更新.

Gre*_*edo 2

看来我犯了一个悲惨的错误。我的代码很好,我的计数不太好。我在绘图中使用了SUMIF()代替COUNTIF(),导致数组中后面的对象(具有更高的索引- UDF 的输出,我应该对其进行计数,但实际上是求和)获得与其位置成比例的权重。

回想起来,我认为比我聪明得多的人可能从所提供的信息中推断出这一点。我说{1,1,1,1}有一个{10%:20%:30%:40%},这是一个 {1:2:3:4} 比率,它与输出索引的比率完全相同,推论:输出被求和而不被计算。

{1,0,0,1}类似地,在输出的图表{20%:0%:0%:80%}中,我们将每个百分比除以它的索引(20%/1, 80%/4),嘿 Presto {20%:0%:0%:20%},或者我预期的 1:1 比率。

有些烦人但又令人满意的事情——知道答案一直就在那里。我想这一切可能都有一个寓意。至少这篇文章可以作为一个警告,提醒初露头角的 VBA 人员检查他们的算术。