我正在进行一些编码练习,但在这个问题上遇到了一些麻烦:
从5个骰子(6面)卷开始,生成[1 - 100]范围内的随机数。
我实现了以下方法,但返回的数字不是随机的(称为函数1,000,000次,而且几个数字从未显示在1 - 100之间)。
public static int generator() {
Random rand = new Random();
int dices = 0;
for(int i = 0; i < 5; i++) {
dices += rand.nextInt(6) + 1;
}
int originalStart = 5;
int originalEnd = 30;
int newStart = 1;
int newEnd = 100;
double scale = (double) (newEnd - newStart) / (originalEnd - originalStart);
return (int) (newStart + ((dices - originalStart) * scale));
}
答案 0 :(得分:7)
好的,所以有5个骰子,每个都有6个选项。如果他们没有订购,你的上述范围是5-30 - 对于1-100来说永远不够。
你需要假设一个订单,这给你一个1,1,1,1,1 - 6,6,6,6,6(基数6)的比例,假设1 - > 0值,您生成一个5位数的基数6。众所周知,6 ^ 5 = 7776独特的可能性。 ;)
为此,我将给你一个有偏见的随机解决方案。
int total = 0;
int[] diceRolls;
for (int roll : diceRolls) {
total = total*6 + roll - 1;
}
return total % 100 + 1;
感谢JosEdu澄清括号要求
此外,如果你想取消偏见,你可以将范围除以上面描述中给出的maxval,然后乘以你的总数(然后加上偏移量),但你仍然需要确定你使用的舍入规则
答案 1 :(得分:1)
问题是5-30中的随机值不足以将一对一映射到1-100区间。这意味着某些价值注定永远不会出现;这些“丢失”值的数量取决于两个区间的大小比例。
然而,您可以通过更有效的方式利用骰子的力量。我就是这样做的:
方法1
方法2
使用base-6系统中的数字构造随机数。 I.E.第一个骰子将是基数6的第一个数字,第二个骰子 - 第二个数字等。
然后转换为base-10,除以(46656/99)。你应该有你的随机数。事实上,你只能使用3个骰子,其余两个只是多余的。
答案 2 :(得分:1)
将6个侧面的模具滚动5次导致6 ^ 5 = 7776个可能的序列,所有这些都是同样可能的。理想情况下,你想要将这些序列分成100个相同大小的组,并且你有[1 - 100] rng,但由于7776不能被100整除,这是不可能的。您可以做的最大限度地减少偏差的是76个组,每个组映射78个序列,每个映射到77个序列的24个组。将(有序)骰子卷编码为基数6,并返回1 +(n%100)。
不仅没有办法用5个骰子卷去除偏差,没有任何骰子卷可以完全消除偏差。没有k的值,其中6 ^ k可被100整除(考虑主要因子分解)。这并不意味着没有办法消除偏见,它只是意味着你不能使用一个保证在任何特定数量的骰子滚动后终止的程序来消除偏差。但是你可以例如做3个骰子卷,产生6 ^ 3 = 216个序列,编码为基数6个数n,如果n <1,则返回1 +(n%100)。 200.问题是,如果n> = 200,你必须重复这个过程,并不断重复,直到你得到n&lt; 200.这样就没有偏见,但是你也可以在循环中停留多长时间。但由于不得不重复的概率每次只有16/216,从实际的角度来看,这并不是一个问题。