Java的随机对象是否通过平等机会创建随机数?

时间:2011-09-04 05:55:36

标签: java random dice

我正在尝试为我编写一个简短的程序来玩骰子游戏(正常的6面骰子)。第一个卷号将添加到乐谱中。在第一次滚动之后,如果我滚动6,则游戏停止并记录得分(不添加6)。如果在第一个掷骰子上滚动6,那很好,并且它像任何其他数字1到5一样被添加。我试图运行这个游戏的一堆迭代,这样我有很长的分数列表(胸围被卷起6)。我将这些分数重新排列为从最小到最大的顺序,然后找到列表的中位数,这是最佳停止的分数。

由于某些原因,我在运行程序时一直保持13,但我知道答案应该是15.在Java中使用Random会对中位数产生某种影响吗?我不完全知道Random如何生成数字以及它是否以平等机会创建它们。还有,那些弹出的东西应该不起作用吗?

import java.util.*;
public class DiceRoller {

private static Random r = new Random();
private static final int games = 10001;
private static int[] totalScores = new int[games];
private static int index = 0;

public static void main(String[] args) {
    int score = 0; boolean firstRoll = true;
    while (index < games) {
        int roll = roll();
        if (firstRoll) {
            score += roll;
            firstRoll = false; 
        } else {
            if (roll == 6) {
                totalScores[index] = score;
                index++; 
                score = 0; firstRoll = true;
            } else {
                score += roll;
            }
        }
    } 
    System.out.println("The median is " + median() + ".");
}

public static int roll() {
    return r.nextInt(6) + 1;
}

public static int median() {
    Arrays.sort(totalScores);
    int temp = totalScores[games / 2];
    return temp;
}

}

3 个答案:

答案 0 :(得分:2)

你得到13,因为这是正确的结果。一点点数学:如果S是表示其中任何一个游戏得分的随机变量,那么您可以考虑f(z)的{​​{3}} S。根据游戏的描述,该概率生成函数满足等式:

f(z) = (z + z^2 + z^3 + z^4 + z^5 + z^6) / 36 + f(z)(z + z^2 + z^3 + z^4 + z^5) / 6

这需要一些思考,或熟悉这种结构:右侧的左手术语考虑了在简单的双掷游戏中获得1到6的概率;涉及f(z)的右手术语考虑了涉及3个或更多卷的游戏,用最终的前6卷(必须在1到5的范围内)和前面的卷表示它们,其概率我们可以再次使用f递归表达。

无论如何,在达到这个目标之后,我们可以重新排列以将f描述为z的合理函数,然后展开为幂级数,开始:

f(z) = 1/36*z + 7/216*z^2 + 49/1296*z^3 + 343/7776*z^4 + 2401/46656*z^5 + 16807/279936*z^6 + 63217/1679616*z^7 + 388087/10077696*z^8 + 2335585/60466176*z^9 + 13681927/362797056*z^10 + 77103313/2176782336*z^11 + 409031959/13060694016*z^12 + 2371648321/78364164096*z^13 + 13583773735/470184984576*z^14 + ...

(我使用Probability generating function来获取此信息。)

系数z^k则描述游戏价值为k的概率;因此,得分为1的概率为1/36,得分为2的概率为216,依此类推。前12个系数的总和是0.472828864487196328...,而前13个系数的总和是0.5030933144224321950968...。所以中位数确实是13。

为了提供一个独立的检查,我写了一个快速的Python程序:

from __future__ import division
import random

def roll():
    return random.randint(1, 6)

def play():
    score = roll()
    while True:
        throw = roll()
        if throw == 6:
            break
        score += throw
    return score

all_scores = sorted(play() for _ in xrange(1000001))
print "median is: ",all_scores[len(all_scores) // 2]
print "fraction of scores <= 12: ",all_scores.index(13) / len(all_scores)
print "fraction of scores <= 13: ",all_scores.index(14) / len(all_scores)

果然,结果如下:

iwasawa:~ mdickinson$ python dice_game.py 
median is:  13
fraction of scores <= 12:  0.472811527188
fraction of scores <= 13:  0.502863497137

所以为了回答你的问题,你所看到的结果并不是Java随机数生成中任何弱点的证据。

答案 1 :(得分:1)

随机并非完全随机且存在一些缺陷。但是对于这个用例,您不太可能注意到这种差异。您可以假设每个值1到6的可能性相同。

为了比较,这里是另一种解决方案,它计算总数的出现次数而不是记录每个值。正如你所看到的,即使你有1000多个游戏,这也表现良好。当您有少量结果和大量重复时,这种方法效果最佳。它是自然分类的。

import java.util.Random;

public class DiceRoller {
  private static final int MAX_VALUE = 300; // assume at most this total
  private static final int GAMES = 10000001;

  public static void main(String... args) {
    int[] count = new int[MAX_VALUE];
    Random rand = new Random();
    for (int i = 0; i < GAMES; i++)
      count[totalScore(rand)]++;
    System.out.println("The median is " + median(count, GAMES) + ".");
  }

  private static int median(int[] count, int games) {
    int findTotal = games/2;
    for (int i = 0; i < count.length; i++) {
      findTotal -= count[i];
      if (findTotal <= 0) return i;
    }
    throw new AssertionError();
  }

  private static int totalScore(Random rand) {
    int total = rand.nextInt(6) + 1;
    for(int n;(n = rand.nextInt(6) + 1) != 6;)
      total += n;
    return total;
  }
}

答案 2 :(得分:0)

以下是一些显示结果分布的代码。它并没有真正回答这个问题,但也许它可以帮助你进行研究。

package so7297660;

import java.util.Random;

public class DiceRoller {

  private static final int N = 10000000;
  private static final Random r = new Random();
  private static final int[] result = new int[100];

  public static int roll() {
    return r.nextInt(6) + 1;
  }

  private static int singleGame() {
    int score = roll();
    while (true) {
      int roll = roll();
      if (roll == 6) {
        return score;
      } else {
        score += roll;
      }
    }
  }

  private static int median() {
    int n = 0;
    for (int i = 0; i < result.length; i++) {
      if (n + result[i] >= N / 2) {
        return i;
      }
      n += result[i];
    }
    throw new IllegalStateException();
  }

  public static void main(String[] args) {
    for (int i = 0; i < N; i++) {
      int score = singleGame();
      int index = Math.min(score, result.length - 1);
      result[index]++;
    }
    for (int i = 0; i < result.length; i++) {
      System.out.println(i + "\t" + result[i]);
    }
    System.out.println("median\t" + median());
  }

}