C++ random number from a set
Asked Answered
D

5

5

Is it possible to print a random number in C++ from a set of numbers with ONE SINGLE statement?

Let's say the set is {2, 5, 22, 55, 332}

I looked up rand() but I doubt it's possible to do in a single statement.

Dioptrics answered 14/3, 2010 at 18:54 Comment(3)
Your question is imprecise. For example i can do it: cout << (rand()%5); indeed prints a random number from a set of 5 numbers with one single statement. How is the set given, is it given at all? And how are the numbers restricted? (must they be able to represent values at least up to INT_MAX, for instance?). Also, notice that a compound-statement is a single statement. Is it a quiz!?Trueblood
Who cares if you can do it in one statement? Tell us why it matters.Achaean
Possible duplicate of How to select a random element in std::set?Tambourine
A
2

Say these numbers are in a set of size 5, all you gotta do is find a random value multiplied by 5 (to make it equi probable). Assume the rand() method returns you a random value between range 0 to 1. Multiply the same by 5 and cast it to integer you will get equiprobable values between 0 and 4. Use that to fetch from the index.

I dont know the syntax in C++. But this is how it should look

my_rand_val = my_set[(int)(rand()*arr_size)]

Here I assume rand() is a method that returns a value between 0 and 1.

Accrue answered 14/3, 2010 at 18:59 Comment(0)
D
11
int numbers[] = { 2, 5, 22, 55, 332 };
int length = sizeof(numbers) / sizeof(int);
int randomNumber = numbers[rand() % length];
Diploid answered 14/3, 2010 at 19:0 Comment(0)
L
5

Pointlessly turning things into a single expression is practically what the ternary operator was invented for (I'm having none of litb's compound-statement trickery):

std::cout << ((rand()%5==0) ? 2 : 
              (rand()%4==0) ? 5 : 
              (rand()%3==0) ? 22 : 
              (rand()%2==0) ? 55 : 
              332
             ) << std::endl;

Please don't rat on me to my code reviewer.

Ah, here we go, a proper uniform distribution (assuming rand() is uniform on its range) in what you could maybe call a "single statement", at a stretch.

It's an iteration-statement, but then so is a for loop with a great big block containing multiple statements. The syntax doesn't distinguish. This actually contains two statements: the whole thing is a statement, and the whole thing excluding the for(...) part is a statement. So probably "a single statement" means a single expression-statement, which this isn't. But anyway:

// weasel #1: #define for brevity. If that's against the rules,
// it can be copy and pasted 7 times below.
#define CHUNK ((((unsigned int)RAND_MAX) + 1) / 5)

// weasel #2: for loop lets me define and use a variable in C++ (not C89)
for (unsigned int n = 5*CHUNK; n >= 5*CHUNK;)
    // weasel #3: sequence point in the ternary operator
    ((n = rand()) < CHUNK) ? std::cout << 2 << "\n" :
             (n < 2*CHUNK) ? std::cout << 5 << "\n" :
             (n < 3*CHUNK) ? std::cout << 22 << "\n" :
             (n < 4*CHUNK) ? std::cout << 55 << "\n" :
             (n < 5*CHUNK) ? std::cout << 332 << "\n" :
             (void)0;
             // weasel #4: retry if we get one of the few biggest values
             // that stop us distributing values evenly between 5 options.

If this is going to be the only code in the entire program, and you don't want it to return the same value every time, then you need to call srand(). Fortunately this can be fitted in. Change the first line to:

for (unsigned int n = (srand((time(0) % UINT_MAX)), 5*CHUNK); n >= 5*CHUNK;)

Now, let us never speak of this day again.

Lomasi answered 14/3, 2010 at 18:54 Comment(4)
Do the multiple calls of rand() keep the probability of each option the same? I'm not that great on probability calculus :)Trueblood
If you ignore the tiny amount of bias introduced if 5! does not evenly divide RAND_MAX, each number is equally probable. Nice! I'll have to remember this... (But I promise not to reveal who I learned it from. :-)Crinite
Looks like it (assuming good results from rand() % N - replace with a better generator as needed). There's a 1 / 5 chance to get 2. There's a (4 / 5) * (1 / 4) = 1 / 5 chance to get 5 etc.Signe
Yes, I made exactly the same assessment as UncleBens did. If we pretend for a moment that rand()%N is a uniformly distributed discrete random variable for N = 2 .. 5, then it doesn't affect the probabilities. Since it isn't, you get slightly different biases from my expression than the biases you would get from the ones which just do a single rand()%5. But nobody has yet bothered to offer a proper uniformly-distributed 5-valued RNG based on a 2^N-valued one. It's bigger than the rest of the question put together, and requires a loop so I think not doable in a single expression.Lomasi
A
2

Say these numbers are in a set of size 5, all you gotta do is find a random value multiplied by 5 (to make it equi probable). Assume the rand() method returns you a random value between range 0 to 1. Multiply the same by 5 and cast it to integer you will get equiprobable values between 0 and 4. Use that to fetch from the index.

I dont know the syntax in C++. But this is how it should look

my_rand_val = my_set[(int)(rand()*arr_size)]

Here I assume rand() is a method that returns a value between 0 and 1.

Accrue answered 14/3, 2010 at 18:59 Comment(0)
I
0

Yes, it is possible. Not very intuitive but you asked for it:

#include <time.h>
#include <stdlib.h>
#include <iostream>

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

    int randomNumber = ((int[]) {2, 5, 22, 55, 332})[rand() % 5];

    std::cout << randomNumber << std::endl;

    return 0;
}    
Impropriate answered 14/3, 2010 at 19:3 Comment(1)
Only as a GCC extension, though. With -pedantic: "warning: ISO C++ forbids compound-literals"Signe
B
0

Your "single statement" criteria is very vague. Do you mean one machine instruction, one stdlib call?

If you mean one machine instruction, the answer is no, without special hardware.

If you mean one function call, then of course it is possible. You could write a simple function to do what you want:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int setSize = 5;
    int set[] = {2, 5, 22, 55, 332 };
    srand( time(0) );

    int number = rand() % setSize;
    printf("%d %d", number, set[number]);
    return 0;
}
Bali answered 14/3, 2010 at 19:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.