最近遇到一个有趣的需求,大概意思就是:编写一个方法,其输出是true或者false,并且该方法调用量很大,我们无法预测每次调用该方法究竟会产生什么结果,但产生true的概率是(或者说非常接近)预先设定好的(比如20%)。
为了实现这个需求,可以采取这样一种思路:
1,建立一个BitSet,size设为100。然后随机产生X个下标,然后将这些下标对应的位置设为true。
2,每次调用该方法时,再产生一个随机数作为下标,然后以此下标取得bitset中指定位置的值,返回。
下面贴一个Java的实现:
首先是产生指定个数的随机下标,TreeSet的一个良好特性就是对于重复的元素,将不会被加入其中
- private List<Integer> makeRndNumbers(int count, int boundry) {
- TreeSet<Integer> set = new TreeSet<Integer>();
- while(set.size() < count) {
- set.add(Math.abs(secRandom.nextInt()) % boundry);
- }
- return new ArrayList<Integer>(set);
- }
假设这个类命名为PercentChoice,其构造方法如下,这里使用了SecureRandom类,这是Java内置的一个安全的随机数发生器。
- public PercentChoice(int percentage) {
- try {
- secRandom = SecureRandom.getInstance("SHA1PRNG");
- secRandom.setSeed(System.currentTimeMillis());
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
- for(Integer i : makeRndNumbers(percentage, 100)) {
- bitSet.set(i, true);
- }
- }
这个方法的代码就非常容易了
- public boolean getOneChoice() {
- return bitSet.get(Math.abs(secRandom.nextInt()) % 100);
- }
最后写个测试的方法
- public static void main(String[] args) throws InterruptedException {
- PercentChoice pc = new PercentChoice(20);
- int hits = 0;
- int times = 10000;
- for(int i = 0; i < times; i++) {
- if(pc.getOneChoice()) {
- hits++;
- }
- }
- System.out.println("Hits percentage " + (double)hits * 100 / (double)times + " %");
- }
在我的机器上反复运行这个测试,其实验结果总是在20%的左右抖动,代码完全满足了需求。
转载于:https://blog.51cto.com/spinlock/447867