Generate a 1000 random integers

Hi everyone,

I’m trying to generate a 1000 random integers number between a and b using the following script:

TRandom *r3 = new TRandom3();
int array[1000];
int a=20000, b=12;
for (i = 0; i < 1000; i++)
{
rand = r3->Rndm(i);
array[i] = a + rand[i] * (a-b);
}

As you can see, this method basically turns the float number rand[i] * (a-b) into the closest integer. The problem is that by doing so, I often obtain the same integer twice…

Therefore, I was wondering if there was a way to generate a 1000 (or more) integers so that the probability of finding the same value twice is extremely low.

Thank you in advance :slight_smile:

K.

1 Like

when I run this macro I do not get any doubling. Note I fixed mistakes in your macro.

{
   TRandom3 *r3 = new TRandom3();
   int array[1000];
   int a=20000, b=12;
   double rrr;
   for (int i = 0; i < 1000; i++) {
      rrr = r3->Rndm(i);
      array[i] = a + rrr * (a-b);
      if (i>0) {
         if(array[i]==array[i-1]) printf ("array[%d] == array[%d] == %d\n",i-1,i,array[i]);
      }
   }
}

Hi Olivier,

thank you for your answer. The only reason why you don’t get any doubling is because you haven’t sorted your array by increasing or decreasing values. Since you compare two values that are stored next to each other, it’s very unlikely that you will find a doubling (it would mean that your RNG has generated twice the same number in a row). Once your array is sorted, you will find doubling by using the same conditions that you wrote.

Cheers,
K.

Yes if I order them I find 30 doublings. But i find you code a bit strange … You said that you want to have random numbers between a and b … but in your case b (12) is smaller than a (20000) . I would have intuitively thought that a should be 12 and b 20000. So I would do:

{
   TRandom3 *r3 = new TRandom3();
   int array[1000];
   int a=12, b=20000;
   double random01;
   for (int i = 0; i < 1000; i++) {
      random01 = r3->Rndm(i);
      array[i] = TMath::Nint(random01*(b-a) + a);
      printf("%d --- %g\n",array[i],random01);
   }
}

Nevertheless some number are stil equal even if the initial random number are diffierrent. Juste because of the rounding. For instance:

12133 --- 0.606396
12133 --- 0.606433

the float result are different before rounding:

root [0] int a=12, b=20000;
root [1] (0.606396*(b-a) + a)
(double) 12132.6
root [2] (0.606433*(b-a) + a)
(double) 12133.4
root [3] 

But TMath::Nint makes them the same … (not it is the came with int, which is what you are doing) . To sort out this issue the only way I can see is to look in the already existing numbers if the new number already exists and in that case reject it.

The easiest thing would be NOT to convert a double number to your range on your own but to use a uniform_int_distribution instead.

In standard c++, you can use:

int a=12, b=20000, numbers_to_generate=1000;
mt19937 mt(random_device{}());
uniform_int_distribution<int> dist(a,b);
vector<int> result;
result.reserve(numbers_to_generate);
set<int> seen;
for (int i = 0; i < numbers_to_generate; ) {
  auto n = dist(mt);
  if (seen.insert(n).second) {
    result.push_back(n);
    ++i;
  }
}

Also, there is TRandom::Uniform(Double_t x1, Double_t x2) if you want uniformly distributed doubles generated by ROOT. You can also use std::uniform_real_distribution instead.

Just to complete the method I suggested you. It would be:

{
   TRandom3 *r3 = new TRandom3();
   bool skip = false;
   int array[1000];
   int a=12, b=20000, rndi, n=0;
   double random01;
   for (int i = 0; i < 1000; i++) {
      random01 = r3->Rndm(i);
      rndi = TMath::Nint(random01*(b-a) + a);
      for (int j = 0; j < i; j++) {
        if (array[j] == rndi) skip = true;
      }
      if (!skip) {
         array[n] = rndi;
         n++;
      }
      skip = false;
   }
}

Now you have the choise. @behrenhoff way is better seems to me.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.