General Programming: random numbers

OK, so I know in C++ and most languages you can get a random number between two values by using the modulo like so:

rand()%(max-min)+min;

However, what if I want to exclude a set of numbers within that range? Say for example I want a random number between 1 and 100 but I want to exclude 45 through 63, so I have 1-45 and 63-100
I see that I can first get a random 0 or 1 to decide whether to get a random int in the lower or higher range, however doing it this way could probably get ugly if I wanted to exclude multiple small ranges of numbers.

Another way might be to take the sum of the allowed ranges, get a random int within that sum, and then distribute it back out to an allowed range

Are there any other methods that you guys can think of which would be better? Any help on this would be appreciated :smiley:

If you do that and the ranges are not of the same size then you will skew the results in favour of one or the other.

What I would do is something along the lines of:


const int ranges[] = {1, 45, 63, 100}
const int COUNT = 2;
int r = 0;
for (int i = 0; i < COUNT; i++) {
   r += ranges[i * 2 + 1] - ranges[i * 2] + 1;
}
int v = rand() % r + ranges[i * 2];
int i = 0;
while (v > ranges[i * 2 + 1]) {
   v += ranges[(i + 1) * 2] - ranges[i * 2 + 1] - 1;
   i++;
}
return v;

Note: I haven’t tested the code so chances are it’s screwy (or my brain is).

EDIT: sorry, didn’t see you’d already suggested this.

Put the random number generator inside a do-while loop and only exit when the number is not between 45 and 63?

i think you should probably add some “if” to the whole thing, like


void main()
{
int a,b;
//for lower range
cin>>a;
//for higher range
cin>>b;
 
//randome subroutine
random(a,b);
 
if(random(a,b)>45 || random(a,b)<63)
              random(a,b);
else
      cout<<random(a,b);
}
 
 

this kinda solves it only if you want to print 1 number, for the lot i think you hsolud use a repetitive call(for,while,do-while)

and btw, i don’t see how this fits in the off-topic forum:) have fun

Problem with such a simple dart throwing mechanism is that it is non-deterministic and so could theoretically run forever, and will run for an unpredictable length of time.

It’s not Python, so I wasn’t sure where to put it :o

Quite alright, I wasn’t sure how to go about doing it anyway :stuck_out_tongue: thanks

And yeah, Surt also cleared up that although a while loop could exit after the first run through, it could also run forever which is really a rather unnecessary risk in this case since there are other, potentially faster and more reliable ways of doing it

#include <iostream>
#include <cmath>
using namespace std;

class range
{
     public:
        double a,b;
};

void sort(range *R,int nr)
{
    int i,j,k;
    double tmp,tmpm,r;

    bool *c;
    c=new bool[nr];
    for(i=0;i<nr;i++) c[i]=1;

    range *R2;
    R2=new range[nr];

    k=0;
    tmpm=R[0].a;

    for(i=0;i<nr;i++) tmpm=max(tmpm,R[i].b);

    for(i=0;i<nr;i++)
    {
        tmp=tmpm;

        for(j=0;j<nr;j++)
        {
            if(c[j])
            {
                if(min(tmp,R[j].a)==R[j].a)
                {
                    k=j;
                    tmp=R[j].a;
                }
            }
        }
        c[k]=0;
        R2[i]=R[k];
    }

    for(i=0;i<nr;i++) R[i]=R2[i];

    delete[] c;
    delete[] R2;
}

double rands(double a,double b,range *R,int nr)
{
    int i,j;
    double r;

    range *R2;
    R2=new range[nr+1];

    R2[0].a=a; R2[0].b=R[0].a;

    for(i=1;i<nr;i++)
    {
        R2[i].a=R[i-1].b;
        R2[i].b=R[i].a;
    }

    R2[nr].a=R[nr-1].b; R2[nr].b=b;

    r=double(rand()%10000)/10000.0;

    double S=0;

    for(i=0;i<=nr;i++) S+=R2[i].b-R2[i].a;

    double *coeff;
    coeff=new double[nr+2];

    coeff[0]=0.0;
    for(i=0;i<=nr;i++) coeff[i+1]=coeff[i]+(R2[i].b-R2[i].a)/S;

    j=0;

    for(i=0;i<=nr;i++) if(r>=coeff[i] && r <=coeff[i+1]) j=i;

    r=R2[j].a+(r-coeff[j])/(coeff[j+1]-coeff[j])*(R2[j].b-R2[j].a);

    /*for(i=0;i<=nr;i++) cout<<R2[i].a<<"  "<<R2[i].b<<endl;

    cout<<S<<endl;

    for(i=0;i<=nr+1;i++) cout<<coeff[i]<<"  ";*/

    delete[] R2;
    delete[] coeff;

    return r;
}

int main()
{
    srand(time(NULL));

    range *R;
    R=new range[5];

    R[2].a=2; R[2].b=3;
    R[0].a=4; R[0].b=7;
    R[1].a=14; R[1].b=16;
    R[4].a=10; R[4].b=11;
    R[3].a=17; R[3].b=18;

    sort(R,5);

    //for(int i=0;i<5;i++) cout<<R[i].a<<" "<<R[i].b<<endl;

    for(int i=0;i<30;i++) cout<<rands(1,20,R,5)<<endl;
}

This algorithm sorts the different ranges, it assumes that all the ranges are within two values and don’t overlap each other.

how about:

a=int(rand(0,1))
if a==1 a=rand(0,45)
else a=rand(63,100)

As Surt said:

damn I should have read the first two posts completly :smiley:

well then how about

a=float(rand(0,1))
if a<=(45-1)/((100-63)+(45-1)) a=rand(1,45)
else a=rand(63,100)

Well, that’s basically what my code does, but with many different ranges.

In delphi (pascal): this should work:

Declare a variable:

<b>var</b>
number: int; 

wherever you want the random number displayed:


<b>procedure</b> TForm1.FormCreate(Sender: TObject);
<b>begin</b>
randomize;
<b>end;</b>
 
<b>procedure</b> TForm1.Button1Click(Sender: TObject);
<b>begin</b>
edit2.text:=floattostr(random(strtoint(edit1.text)));
<b>end;</b>

that will allow you to enter the top value ie, 0-x

if you want to have 10-100, 20-100 etc, then add a plus ‘x’

(random(strtoint(edit1.text))+10);

and that should do it.

I hope I helped :wink: