java - 单元测试随机数java

标签 java algorithm unit-testing random statistics

我的目标是测试一个类是否将其属性之一设置为随机整数值。我在网上找到了一种卡方检验算法,并决定使用它。我对结果感到非常惊讶:我的样本量越大,测试通过的可能性就越小。我应该说我绝不是统计专家(我问这个问题可能是不言而喻的)所以我在这里可能会弄错一些东西。

仅改变最终 int SIZE 的测试结果(在 UserTest 中)。每个测试运行 30 次:

SIZE    avg     results

11      25.4    26, 25, 22, 24, 30

20      25      26, 26, 24, 22, 27

30      24      24, 22, 24, 26, 24

100     19.4    17, 23, 20, 18, 19

200     16.2    15, 18, 18, 15, 15

1000    13.2    13, 13, 14, 13, 13

10000   10      14, 7, 8, 10, 11

虽然在这种情况下我并不是绝对需要真正的随机性,但我仍然很好奇问题是什么。这本身是一个错误的算法,我对它的错误使用,是“让测试更难”的自然结果(统计菜鸟,记住),还是我突破了 Java 伪随机生成器的界限?

领域类:

public class User
{
  public static final int MINIT = 20;
  public static final int MAXIT = 50;
  private int iterations;

  public void setIterations()
  {
    Random random = new Random();
    setIterations(MINIT+random.nextInt(MAXIT-MINIT));
  }

  private void setIterations(int iterations) {
    this.iterations = iterations;
  }
}

测试类:

public class UserTest {

  private User user = new User();

  @Test
  public void testRandomNumbers() {
    int results = 0;
    final int TIMES = 30;
    for(int i = 0; i < TIMES; i++)
    {
      if (randomNumbersRun())
      {
        results++;
      }
    }
    System.out.println(results);
    Assert.assertTrue(results >= TIMES * 80 / 100);
  }

  private boolean randomNumbersRun()
  {
    ArrayList<Integer> list = new ArrayList<Integer>();
    int r = User.MAXIT - User.MINIT;
    final int SIZE = 11;
    for (int i = 0; i < r*SIZE; i++) {
      user.setIterations();
      list.add(user.getIterations());
    }
    return Statistics.isRandom(list, r);
  }
}

卡方算法:

  /**
   * source: http://en.wikibooks.org/wiki/Algorithm_Implementation/Pseudorandom_Numbers/Chi-Square_Test
   * changed parameter to ArrayList<Number> for generalization
   */
  public static boolean isRandom(ArrayList<? extends Number> randomNums, int r) {
    //According to Sedgewick: "This is valid if N is greater than about 10r"
    if (randomNums.size() <= 10 * r) {
      return false;
    }

    //PART A: Get frequency of randoms
    Map<Number, Integer> ht = getFrequencies(randomNums);

    //PART B: Calculate chi-square - this approach is in Sedgewick
    double n_r = (double) randomNums.size() / r;
    double chiSquare = 0;

    for (int v : ht.values()) {
      double f = v - n_r;
      chiSquare += f * f;
    }
    chiSquare /= n_r;

    //PART C: According to Swdgewick: "The statistic should be within 2(r)^1/2 of r
    //This is valid if N is greater than about 10r"
    return Math.abs(chiSquare - r) <= 2 * Math.sqrt(r);
  }

  /**
   * @param nums an array of integers
   * @return a Map, key being the number and value its frequency
   */
  private static Map<Number, Integer> getFrequencies(ArrayList<? extends Number> nums) {
    Map<Number, Integer> freqs = new HashMap<Number, Integer>();

    for (Number x : nums) {
      if (freqs.containsKey(x)) {
        freqs.put(x, freqs.get(x) + 1);
      } else {
        freqs.put(x, 1);
      }
    }

    return freqs;
  }
}

最佳答案

看起来你的测试在执行 Random 时发现了一个错误在你的平台上。根据documentation , 调用 new Random()没有参数应该

set the seed of the random number generator to a value very likely to be distinct from any other invocation of this constructor.

在实践中,这是通过将“随机化系数”添加到以纳秒为单位的当前时间,然后根据一些简单算法将随机化系数更改为新值来实现的。但是,确切的实现是特定于您的 Java 平台的。

因为在丢弃 Random 之前您只获得了第一个伪随机数对象,您的测试取决于不同随机算法的结果:而不是测试 Random 有多好本身,您的算法正在有效地测试它的随机种子选择器有多好。

自制作Random一个static User的成员class 已经解决了这个问题,并且由于在另一个平台上的结果不同 ( link to code on ideone showing different results ) 看来

  • 在您的平台上生成伪随机数的算法优于在您的平台上为伪随机数生成器生成种子的算法
  • 以上内容特定于您的平台,因为在其他平台上,种子生成器也是相当随机的。

关于java - 单元测试随机数java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21216584/

相关文章:

c# - 如何对私有(private)属性进行单元测试?

python - isinstance 和 Mocking

java - Android 中仅客户端套接字编程

java - 是否可以在java中将JFrame添加到JPanel中?

java - TA-LIB Mama 指示器的结果不正确

algorithm - 有向图中一组顶点的距离

java - Java中的静态变量

algorithm - 在次二次时间删除 "almost duplicate"字符串

c# - 进行字符串连接时的性能 - 算法字符串字符串 c#

android - android.unitTests.returnDefaultValues 是如何工作的?