如何使用一对六面骰子创建一个有偏差的数字生成器

时间:2010-02-15 03:11:44

标签: algorithm math puzzle

使用一对六面骰子以[1,4]不均匀生成随机数的最有效方法是:在40%的时间内产生1,在30%中产生2,在20%中产生3和10%中的4%。

请证明方法的正确性并给出算法。

骰子可能有不同的颜色。

注意:唯一可用的随机数发生器是两个颜色不同的六面骰子。

8 个答案:

答案 0 :(得分:8)

假设两个骰子:一个白色骰子。

  1. 滚动两个骰子,给你两个数字,从1到6;
  2. 创建一个新号码:6 *(白色骰子 - 1)+黑色骰子
  3. 这个数字在1到36之间。如果它高于30则转到2并重复;
  4. 现在你有你需要的东西:

    • 1-12 = 1(12/30 = 40%)
    • 13-21 = 2(9/30 = 30%)
    • 22-27 = 3(6/30 = 20%)
    • 28-30 = 4(3/30 = 10%)

    您需要的不是4种可能的结果,而是10种因为它可以代表您想要的加权结果。两个骰子可以通过多种方式产生36种可能性,但你需要的是10或10的倍数,如上所述。

    这种方法的唯一缺点是它是概率性的(意味着你可以在技术上永远地重新定位31+),但我不相信存在确定性和准确的解决方案。

答案 1 :(得分:2)

关键:“它应该在40%的时间内产生1%,2%在30%,3%在20%,4%在10%”

一对6面骰子有36种可能的结果。 红色,蓝色(假设有一些骰子的区别)
1 1
1 2
1 3
1 4
1 5
1 6
2 1
2 2
2 3
2 4
2 5
2 6
3 1
3 2
3 3
3 4
3 5
3 6
4 1
4 2
4 3
4 4
4 5
4 6
5 1
5 2
5 3
5 4
5 5
5 6
6 1
6 2
6 3
6 4
6 5
6 6

36个结果中有10%分解为3.6个结​​果......这是不可能的,所以你要抛出六个结果来得到30个结果,这个结果可以除以10.为了方便起见,抛弃重复的角色( 1-1,2-2,3-3,4-4,5-5,6-6)

现在,如果有3个结果,则为10%的单位。现在你的垃圾箱[1-4]需要适当数量的结果来弥补40%,30%,20%,10%。

..或
40%= 12/30结果...所以采取前12个案例..记住重复删除=(1,2)到(3,2)
30%= 9/30结果......接下来的9个结果=(3,4)到(5,1)
20%= 6/30结果......接下来的6个结果=(5,2)到(6,2)
10%= 3/30结果......取最后3个结果=(6,3)到(6,5)

..现在的问题是,任何重复的滚动都会强制重新滚动,这可能会反复发生,所以效率不高。问题是基础6(骰子)和基础10(10%= 1/10)是缺乏一个更好的术语 - 相互补充。这与二进制中表示1/10的问题相同。无论您使用多少钻头,您都只能靠近=无论有多少卷,您都无法使用6面模具生产出完美的10%垃圾箱。

你必须使用5或10面死。

答案 2 :(得分:2)

正如其他人所指出的那样,没有一种解决方案可以100%有效地工作,你必须使用拒绝抽样。

一般来说,我是第二个Cletus的答案,但是使用他的算法,你将从两个骰子获得一个概率为5/6的结果,这意味着预期的“每个骰子的结果数”是5/12~ = 0.417。将后者乘以你的一个随机结果的熵,

-(0.1*log2(0.1) + 0.2*log2(0.2) + 0.3*log2(0.3) + 0.4*log2(0.4)) ~= 1.846
我们获得0.770。换句话说,我们平均每个芯片使用0.770位信息。我们可以比这更好。

例如,投掷9个骰子,你有6 ^ 9 = 10077696可能的结果。在Cletus之后,形成一个从0到10077695的数字,并且只有在介于0和9999999之间时才保留它(这种情况发生的概率为~0.992)。在这种情况下,你有7个随机十进制数字,均匀分布,你可以从你的问题中提取一个随机数:

0,1,2,3 --> 1
4,5,6   --> 2
7,8     --> 3
9       --> 4

这样,我们每9个骰子有7个随机结果,概率为0.992,或平均“每个骰子的结果数”为0.992 * 7 / 9~ = 0.772。将其乘以结果的熵,我们得到1.846 * 0.772~ = 1.425。因此,通过这种方式,我们平均每个芯片使用1.425位。

我们可能会更好地投掷更多骰子或采用其他技术。当然,上限是骰子的熵,即log2(6)〜= 2.585位。

答案 3 :(得分:1)

一种方法是生成一个随机整数,并将其用作指定概率的数组的索引。

例如,以下的伪代码将产生1 2 / 3rds的时间,以及2 1/3的时间。

var randArray = [1, 1, 2];
var randIndex = random(2);
return randArray[randIndex];

答案 4 :(得分:1)

我做其他人的作业感觉不太好,但我可以给出一个提示:看看this graph并从那里开始工作。

答案 5 :(得分:1)

这是我为biased roulette wheel for a genetic algorithm编写的一个骰子,但可以进行调整。它位于C#中,但很容易更改为Java或其他基于C语言。

首先从一组值开始
如果要复制实际骰子,请将这些值换成数字1-6。

double[] values =
{
    9,
    66,
    153,
    2,
    42,
    34
};

然后添加您希望每个百分比显示的百分比 例如,您希望153有偏差,因此在25%的时间内选择它:

double[] percentages = 
{ 
    15, 
    10, 
    25, 
    5, 
    37, 
    8 
};

现在设置一些百分比范围。
这用于掷骰子,所以如果滚动15-25,你知道它落在第二个百分比范围内。

double[] ranges = new double[6];
ranges[0] = percentages[0];
ranges[1] = ranges[0] + percentages[1];
ranges[2] = ranges[1] + percentages[2];
ranges[3] = ranges[2] + percentages[3];
ranges[4] = ranges[3] + percentages[4];
ranges[5] = ranges[4] + percentages[5];

最后,生成一个随机数。
如果该数字落在其中一个范围之间,请从值中选择该索引。

static Random _random = new Random();

static void Main(string[] args)
{
    ...

    for (int i = 0; i < percentages.Length; i++)
    {
        int rand = _random.Next(0, 100);
        double x = ranges.First(n => n >= rand);
        int index = ranges.ToList().IndexOf(x);
        Console.WriteLine(values[index]);
    }
}

我确信有办法改善这一点,我很想知道它们。

答案 6 :(得分:0)

使用标记为1,1,1,1,2,2,2,3,3,4的10面模具。或者你(由于某种原因)限于六面骰子?有关计算机实现,请参阅Benny Jobigan的回答。

但是,如果你只限制两个六面骰子,一种方法是制作36张小方卡。标记12标记为“1”,标记9标记为“3”,标记3标记为“4”,标记3标记为空白或标记为“重新翻滚”。

将36张卡片放在一个6x6的方格中。使用数字1-6标记每一行和每列,并确定哪些模具对应于列以及哪些行。

掷骰子,找到与所选行和列对应的卡片。如果卡上有一个号码,那就是你想要的号码,如果它是空白的(或说“重新滚动”),再次掷骰子。

请注意,网格上数字的确切位置对于公平骰子无关紧要,但对于有偏见的骰子会给出不同的结果。

答案 7 :(得分:0)

由于此作业可能已经过时,我会给出答案:我们的想法是逐步完善你的卷,直到你可以确定选择了哪种颜色。

首先,将范围从0到1划分为与概率相对应的块:在数字线上标记0.4,0.7,0.9和1.0,它们定义标记为1到4的区域。您需要跟踪数字你掷骰子的时间,n和跑步的计数器,p。最初,设置n = 1,p = 0。

  1. 掷骰子并除以6 * n,并将此值添加到p。在数字线上标记这个位置。
  2. 如果p和p + 1 / 6n位于相同的“区域”(它们没有穿过您在上面定义的边界),则表示您已完成,颜色是p所在区域的颜色。
  3. 否则递增n并转到1.
  4. 这样一来,大多数时候你只需要一两卷来确定选择哪种颜色,尽管如果你最终靠近边界,你将不得不滚动更多。使用你的重量,40%的时间你只需要1次滚动,44%的时间你需要2次,13%你需要3次,大约3%的时间你需要更多。