views:

380

answers:

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 double it's possible to do in a single statement

+2  A: 

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.

Bragboy
Replace multiplies with modulo and you'll be good (almost).
UncleBens
@Jim Lewis: I guess I corrected the answer
Bragboy
Jim Lewis
+7  A: 
int numbers[] = { 2, 5, 22, 55, 332 };
int length = sizeof(numbers) / sizeof(int);
int randomNumber = numbers[rand() % length];
Li0liQ
A: 

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;
}    
AndiDog
Only as a GCC extension, though. With -pedantic: "warning: ISO C++ forbids compound-literals"
UncleBens
A: 

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;
}
Casey
+5  A: 

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.

Steve Jessop
Do the multiple calls of `rand()` keep the probability of each option the same? I'm not that great on probability calculus :)
Johannes Schaub - litb
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. :-)
Jim Lewis
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.
UncleBens
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.
Steve Jessop