最近遇到一个有趣的需求,大概意思就是:编写一个方法,其输出是true或者false,并且该方法调用量很大,我们无法预测每次调用该方法究竟会产生什么结果,但产生true的概率是(或者说非常接近)预先设定好的(比如20%)。
 

为了实现这个需求,可以采取这样一种思路:

1,建立一个BitSet,size设为100。然后随机产生X个下标,然后将这些下标对应的位置设为true。 

2,每次调用该方法时,再产生一个随机数作为下标,然后以此下标取得bitset中指定位置的值,返回。

下面贴一个Java的实现:
 

首先是产生指定个数的随机下标,TreeSet的一个良好特性就是对于重复的元素,将不会被加入其中

 
    
  1. private List makeRndNumbers(int count, int boundry) {  
  2.     TreeSet set = new TreeSet();  
  3.     while(set.size() < count) {  
  4.         set.add(Math.abs(secRandom.nextInt()) % boundry);  
  5.     }  
  6.       
  7.     return new ArrayList(set);  

 假设这个类命名为PercentChoice,其构造方法如下,这里使用了SecureRandom类,这是Java内置的一个安全的随机数发生器。

 
    
  1. public PercentChoice(int percentage) {  
  2.     try {  
  3.         secRandom = SecureRandom.getInstance("SHA1PRNG");  
  4.         secRandom.setSeed(System.currentTimeMillis());  
  5.     } catch (NoSuchAlgorithmException e) {  
  6.         e.printStackTrace();  
  7.     }  
  8.       
  9.     for(Integer i : makeRndNumbers(percentage, 100)) {  
  10.         bitSet.set(i, true);  
  11.     }  

这个方法的代码就非常容易了

 
    
  1. public boolean getOneChoice() {  
  2.     return bitSet.get(Math.abs(secRandom.nextInt()) % 100);  

最后写个测试的方法

 
    
  1. public static void main(String[] args) throws InterruptedException {  
  2.     PercentChoice pc = new PercentChoice(20);  
  3.     int hits = 0;  
  4.     int times = 10000;  
  5.     for(int i = 0; i < times; i++) {  
  6.         if(pc.getOneChoice()) {  
  7.             hits++;  
  8.         }  
  9.     }  
  10.     System.out.println("Hits percentage " + (double)hits * 100 / (double)times + " %");  

在我的机器上反复运行这个测试,其实验结果总是在20%的左右抖动,代码完全满足了需求。