gpt4 book ai didi

java - 单元测试随机数java

转载 作者:搜寻专家 更新时间:2023-10-31 20:12:03 26 4
gpt4 key购买 nike

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

仅改变最终 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/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com