|
本帖最后由 香川群子 于 2014-8-31 23:00 编辑
具体请看附件,不懂来问。
附件更新,改为自定义函数版用法:
香川巨量随机取数20140828.rar
(23.83 KB, 下载次数: 506)
- Sub kagawa()
- If [g2] = 0 Then [g2] = 5 '列数指定不能为0
- [a5].CurrentRegion.Offset(1) = "" '清空输出区域
- [a6].Resize([c2] \ [g2] + 1, [g2]) = GetRndAvg([a2], [b2], [c2], [d2], [e2], [h2], [g2]) '按指定列数输出结果
- End Sub
- Function GetRndAvg(a, b, m, Optional d = 0, Optional h = 1, Optional s = 1, Optional l = 5) '指定区间内 均匀随机取不重复值 按指定列数输出
- ' Dim a, b, c(), d, f(), h, i, l, m, n, r, t '因为数值个数会超Long范围,所以不应该定义数据类型
- ' [f2]=IF(E2,INT((B2-A2)*10^D2/E2)+1,"无限")
-
- ' d = [d2] '小数位数d 用法同=Round(,numdecimalplaces)的第2参数 零为整数、正数为小数、负数为个十百千位向上取整
- ' a = [a2] * 10 ^ d '取值下限、自动按小数位设置扩大/缩小
- ' b = [b2] * 10 ^ d '取值上限、自动按小数位设置扩大/缩小
- ' m = [c2] '取值个数 F2单元格中公式计算取值允许个数 =IF(E2,INT((B2-A2)*10^D2/E2)+1,"无限")
- ' h = [e2] '最小间隔步长 h=0时允许重复。而h不为零时如取值个数大于取数范围则取数不足部分返回=0
- ' l = [g2] '输出时列数指定 行数自动=m\l
- ' s = [h2] '输出时是否排序 s=0时返回随机乱序(数组洗牌法)、s=1时按从小到大升序输出
- a = a * 10 ^ d
- b = b * 10 ^ d
-
- Randomize
- ReDim c(m - 1) '按取值个数定义存放结果的数组c
- If b - a < m * h Then c(0) = a Else c(0) = Int(((b - a + 1) / m - h) * Rnd) + a '首位取值*Rnd即可
- ' n = 0 当前取值个数
- Do
- If b - c(n) < (m - n) * h Then
- If c(n) + h > b Then Exit Do Else c(n + 1) = c(n) + h
- Else
- c(n + 1) = c(n) + Int(((b - c(n) + 1) / (m - n) - h) * Rnd * 2) + h
- '取数原理为: 上个值c(n) + 剩余范围(b - c(n) + 1) 除以剩余个数(m - n)得到的均匀区间
- ' 并扣除最小间隔h然后 乘以2倍随机数 Rnd*2 取值 再加上最小间隔h
- '其中关键是 要乘以2倍随机数 Rnd*2 取值 这是因为Rnd的期望平均值=0.5
- End If
- n = n + 1
- Loop Until n = m - 2 '到剩下最后一个时停止 (因最后一个的计算方法不同)
- If c(n) + h <= b Then c(m - 1) = c(n) + Int((b - c(n) + 1 - h) * Rnd) + h '末位取值*Rnd即可
-
- ReDim f(m \ l, l - 1) '按指定列数计算所需行数后定义存放结果的数组f
- If s = 0 Then 's=0时返回随机乱序(数组洗牌法)
- For i = 0 To m - 1
- r = Int((m - i) * Rnd) + i '数组洗牌算法进行不重复随机乱序抽取
- f(i \ l, i Mod l) = c(r) / 10 ^ d '该随机位置结果按指定小数位换算后输出
- c(r) = c(i) '该随机位置和当前位置值交换 防止遗漏
-
- ' t = c(r): c(r) = c(i): c(i) = c(r) '抽取后进行位置交换 保证不重复以及无遗漏
- ' f(i \ l, i Mod l) = t / 10 ^ d '结果按指定小数位换算
- Next
- Else 's=1时按从小到大升序输出
- For i = 0 To m - 1
- f(i \ l, i Mod l) = c(i) / 10 ^ d '结果按指定小数位换算
- Next
- End If
-
- ' [a5].CurrentRegion.Offset(1) = "" '清空输出区域
- ' [a6].Resize(m \ l + 1, l) = f '按指定列数输出结果
- GetRndAvg = f '数组结果赋值给该函数
-
- End Function
复制代码 |
评分
-
6
查看全部评分
-
|