|
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用 · 内置多项VBA编程加强工具 ★ 免费下载 ★ ★ 使用手册★
aoe1981 发表于 2014-5-5 09:07
法师,利用字典实现随机数的去重不是很方便吗?过一会再研究一下……
我很早以前就研究过此问题。
只是没有公开发布而已。
今天正好看到此贴,就正式发布一下。
- Sub kagawa() '指定区间内 均匀随机取不重复值 按指定列数输出
- ' Dim a, b, c(), d, f(), h, i, l, m, n, r, t '因为数值个数会超Long范围,所以不应该定义数据类型
-
- 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
- r = [h2] '输出时是否排序 r=0时返回随机乱序(数组洗牌法)、r=1时按从小到大升序输出
-
- 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 r = 0 Then 'r=0时返回随机乱序(数组洗牌法)
- For i = 0 To m - 1
- r = Int((m - i) * Rnd) + i '数组洗牌算法进行不重复随机乱序抽取
- t = c(r): c(r) = c(i): c(i) = c(r) '抽取后进行位置交换 保证不重复以及无遗漏
- f(i \ l, i Mod l) = t / 10 ^ d '结果按指定小数位换算
- Next
- Else 'r=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 '按指定列数输出结果
-
- End Sub
复制代码
香川巨量随机取数20140828.rar
(22.55 KB, 下载次数: 84)
|
评分
-
2
查看全部评分
-
|