如何使随机数唯一

时间:2014-04-13 23:33:45

标签: c++

我正在制作一个随机数生成器。它询问用户想要多少位数。例如,它输入2它将产生10到99之间的随机数。我已经制作了发生器,但我的问题是数字不是唯一的。

这是我的代码。我不确定为什么它没有产生唯一的数字。我认为srand(time(null))会这样做。

void TargetGen::randomNumberGen()
{
srand (time(NULL));
if (intLength == 1)
{

    for (int i = 0; i< intQuantity; i++)
    {
        int min = 1;
        int max = 9;
        int number1 = rand();

        if (intQuantity > max)
        {
            intQuantity = max;
        }

        cout << number1 % max + min << "\t";

    }

}
else if (intLength == 2)
{
    for (int i = 0; i<intQuantity; i++)
    {
        int min = 10;
        int max = 90;
        int number1 = rand();

        if (intQuantity > max)
        {
            intQuantity = max;
        }

        cout << number1 % max + min << "\t";


    }

}

if (intLength == 3)
{
    for (int i = 0; i<intQuantity; i++)
    {
        int min = 100;
        int max = 900;
        int number1 = rand();

        if (intQuantity > max)
        {
            intQuantity = max;
        }

        cout << number1 % max + min << "\t";
    }

}
else if (intLength == 4)
{
    for (int i = 0; i<intQuantity; i++)
    {
        int min = 1000;
        int max = 9000;
        int number1 = rand();

        if (intQuantity > max)
        {
            intQuantity = max;
        }

        cout << number1 % max + min << "\t";
    }

}

if (intLength == 5)
{
    for (int i = 0; i<intQuantity; i++)
    {
        int min = 10000;
        int max = 90000;
        int number1 = rand();

        if (intQuantity > max)
        {
            intQuantity = max;
        }

        cout << number1 % max + min << "\t";
    }

}
else if (intLength == 6)
{

    for (int i = 0; i<intQuantity; i++)
    {
        int min = 100000;
        int max = 900000;
        int number1 = rand();

        if (intQuantity > max)
        {
            intQuantity = max;
        }

        cout << number1 % max + min << "\t";


    }

}

if (intLength == 7)
{
    for (int i = 0; i<intQuantity; i++)
    {
        int min = 1000000;
        int max = 9000000;
        int number1 = rand();

        if (intQuantity > max)
        {
            intQuantity = max;
        }

        cout << number1 % max + min << "\t";
    }

}
else if (intLength == 8)
{
    for (int i = 0; i <intQuantity; i++)
    {
        int min = 10000000;
        int max = 89999999;
        int number1 = rand();

        if (intQuantity > max)
        {
            intQuantity = max;
        }

        cout << number1 % max + min << "\t";
    }

}

if (intLength == 9)
{
    for (int i = 0; i < intQuantity; i++)
    {
        int min = 100000000;
        int max = 900000000;
        int number1 = rand();

        if (intQuantity > max)
        {
            intQuantity = max;
        }

        cout << number1 % max + min << "\t";
    }

}
}

好吧所以我想我找到了一种没有阵列的方法,但是在我切换到fisher yates方法之前它还没有工作。有人能告诉我为什么这不起作用吗?它应该基本上把随机数放入变量numGen。然后在变量b =到numgen。只是为了保持numGen曾经是这样,当循环通过并生成另一个随机数时,它会将它与旧数字进行比较,如果它不等于它,那么它将输出它。如果它等于旧的数字而不是输出它,它将减去i,使其在没有完全跳过数字的情况下运行循环。但是,当我这样做时,无限循环。而且我不确定为什么。

if(intLength == 1)     {

    for (int i = 0; i< intQuantity; ++i)
    {

        int min = 1;
        int max = 9;
        int number1 = rand();
        int numGen = number1 % max + min;


        if (intQuantity > max)
        {
            intQuantity = max;
        }

        for (int k = 0; k < 1; k++)
        {
            cout << numGen << "\t";
            int b = numGen;
        }
        int b = numGen;
        if (b != numGen )
        {
            cout << numGen << "\t";
        }
        else
        {
            i--;
        }

    }

}

6 个答案:

答案 0 :(得分:2)

每个人都对随机数有一个有趣的期望 - 显然,你希望随机数是唯一的!如果您使用任何随机数生成器,您的随机数将 永远 保证是唯一的。

为了使这一点最明显,如果你想生成[1,2]范围内的随机数,并且你要生成两个数字,你会(通常期望)以相同的概率得到以下四种可能之一:

1,2 2,1 1,1 2,2,

要求一个好的随机数生成器生成前两个,而不是最后两个生成没有意义。

现在,如果你要求在同一范围内生成三个数字,请花一点时间思考会发生什么...... 1,2,然后是什么?

因此,唯一性不是,也不会是随机数生成器的属性。

但是,您的具体问题可能需要独特性。在这种情况下,您需要做一些额外的工作以确保唯一性。

一种方法是保留一个已经选择了数字的标签。你可以将它们保存在一个集合中,如果你得到了之前的那个,就重新挑选它们。但是,只有当您选择与您的范围相比较少的一组数字时,这才有效;如果你选择了大部分范围,那么这个过程的结束就会失效。

如果你要选择的数字计数对应于大部分范围,那么使用范围的数组,并使用一个好的改组算法来改变数字周围是一个更好的解决方案。 (Fisher-Yates shuffle应该可以解决问题。)

答案 1 :(得分:2)

提示0: 使用数论中的 Quadratic residue ;整数 q 被称为二次余数模 p ,如果它与完全平方模 p 一致;即,如果存在整数 x ,则:

x 2 ≡q(mod p)

提示1: 定理:假设p是素数,x的二次余数是唯一的,只要2x <1。页。例如:

  

0 2 ≡0(mod 13)

     

1 2 ≡1(mod 13)

     

2 2 ≡4(mod 13)

     

3 2 ≡9(mod 13)

     

4 2 ≡3(mod 13)

     

5 2 ≡12(mod 13)

     

6 2 ≡10(mod 13)

提示2: 定理:假设p是素数,使得p≡3(mod 4),不仅x 2 %p(即二次余数)对于2x <1是唯一的。 p,但p-x 2 %p对于2x> p也是唯一的。例如:

  

0 2 %11 = 0

     

1 2 %11 = 1

     

2 2 %11 = 4

     

3 2 %11 = 9

     

4 2 %11 = 5

     

5 2 %11 = 3

     

11 - 6 2 %11 = 8

     

11 - 7 2 %11 = 6

     

11 - 8 2 %11 = 2

     

11 - 9 2 %11 = 7

     

11 - 10 2 %11 = 10

因此,这种方法在小于p的整数上为我们提供了完美的1对1排列,其中p可以是任何素数,使得p≡3(mod 4)。

提示3:

unsigned int UniqueRandomMapping(unsigned int x)
{
    const unsigned int p = 11; //any prime number satisfying p ≡ 3 (mod 4)
    unsigned int r = ((unsigned long long) x * x) % p;
    if (x <= p / 2) return r;
    else return p - r;
}

我并不担心输入数字不好(例如超出范围)。

<强>说明

  • 对于32位整数,您可以选择最大素数,使p≡3(mod 4)小于2 32 ,即4294967291.
  • 即使这种方法为您提供了一对一的映射来生成随机数,它也会遇到群集问题。
  • 为了改善上述方法的随机性,将其与之组合 其他独特的随机映射方法,如XOR运算符。

答案 2 :(得分:1)

我假设您可以想出一个方法来确定您想要使用多少个数字。它非常简单,因为2的用户输入为10-99,3为100-999等。

如果您想要自己实现独特的,随机生成的数字,请查看这些链接。

http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

这是一个非常类似的实现:https://stackoverflow.com/a/196065/2142219

本质上,您正在创建一个X整数数组,所有这些都设置为其索引的值。您可以随机选择介于0和MAX之间的索引,获取此索引处的值并将其与最大值进行交换。然后将MAX递减1,您可以通过随机选择0和MAX之间的索引重复它。

这为你提供了一个0-999整数的随机数组,没有重复。

答案 3 :(得分:0)

以下是在范围内生成唯一随机数的两种可能方法。

  1. 使用std::set跟踪您已经生成的数字,只要它们已经在集合中,就会丢弃并重新生成数字。由于生日悖论,如果你想生成大量的随机数,这种方法不推荐
  2. 生成给定范围内的所有数字,对它们进行随机排列,然后输出用户想要的数量。

答案 4 :(得分:0)

标准随机生成器永远不会生成唯一的数字,在这种情况下,它们不会是独立的。

要生成唯一的数字,您必须:

  • 保存生成的所有数字,并将旧的数字与旧的数字进行比较,如果有巧合 - 重新生成。

答案 5 :(得分:0)

首先,srand() / rand() 通常的周期为2 ^ 32,这意味着在调用srand()之后,rand()会在内部在对rand()的前2 ^ 32次调用期间迭代不同的整数。尽管如此,rand()可能会返回少于32位的结果:例如int0之间的RAND_MAX,其中RAND_MAX为2 ^ 31-1或2 ^ 15-1,因此您可能会看到重复的结果作为rand()的来电者。你可能已经读过这个时期,或者有人意识到这一点,并且不知怎的,它被误认为是唯一性......

其次,如果对rand()的任何调用产生的数字远远大于您想要的数字,那么您就是这样做了......

number1 % max

&#34; number1 % max&#34;的结果在0 <= N <= max范围内,但随机数本身可能是max的任意倍数。换句话说,两个不同的随机数相差max的倍数,仍然会在程序中为number1 % max生成相同的结果。


要获得某个范围内的不同随机数,您可以使用所有数字预填充std::vector,然后std::shuffle