0

Story: Using rand() function in C++, I can get random numbers, and using % I can set the range. However, If I also want to add bias, then I also have to add bias to the result. This is too much work to do, so I decided to write my own function to handle this. However I am stuck at one point.

I know that, I have to feed a new sequence(srand(time(NULL))) each time the program runs, otherwise I will get same numbers all the time.

The obvious way to do this is, to insert srand(time(NULL)) in the main() function. However, I don't want to do that, I want somehow it gets done automatically when I include my .h file.

Suppose myFunctions.h:

#include <iostream> #include <string> #include <vector> #include <cstdio> #include <ctime> int randint(int start, int end); 

and myFunctions.cpp:

#include "myFunctions.h" /* [start,end) */ int randint(int start, int end) { return (rand() % (end - start)) + start; } 

Now, I am confused where I should add srand(). If I do it in randint() definition, I assume, because of the fact that time difference will be too low, time(NULL) will evaluate the same value for each step of the loop and it will feed the same seed all the time when I want to get random numbers in a very short time, like:

for(int i = 0; i < 50; i++){ std::cout << randint(0, 3) << std::endl; } 

The output is the same number, 50 times. So it confirms my suspicion.

I have tried something like this in my randint() definition,

int randint(int start, int end) { #ifndef SEED srand(time(NULL)); #define SEED #endif return (rand() % (end - start)) + start; } 

However, it did not work too, because, I assume, the #ifndef only executes once at preprocessing stage.

So, after these attemps, I tried to call srand() right at the beginning of my .h file, but I came across with the fact that, actually you cannot call functions outside any function(main() for example.)

In short, I am stuck right now, any help will be appreciated.

7
  • 3
    Just manually call srand() at the beginning of your program Commented Apr 11, 2020 at 10:47
  • @michaeldel yes, it solves, but all this question asking is about avoiding it, if possible. Commented Apr 11, 2020 at 10:47
  • 1
    Don't use rand. Use en.cppreference.com/w/cpp/header/random. rand is an old function from C times and should be avoided. Commented Apr 11, 2020 at 10:48
  • @Mannoj if you examine my question, you can see that I don't have a problem understanding those things... Commented Apr 11, 2020 at 10:48
  • @ThomasSablik I will have a look at that, thanks. Commented Apr 11, 2020 at 10:49

2 Answers 2

1

If I were you, I would implement a class to wrap all the functions in. You could call it randomGen or something like that and then include all the functions you want to use inside of that class. Then include a constructor that calls srand(). Then you can create a randomGen object in main and then you can go ahead and generate your random numbers.

Sign up to request clarification or add additional context in comments.

2 Comments

If calling the constructor in the main was desirable, then I would simply put everything in a config() function and would call it rather than creating a class. Thanks for the answer, though
I don't think there are any other ways to achieve this, you may be able to do something with pre-processor commands, but the solution would be messy. Thanks!
0

Use the call_once function available from C++11 onward. This requires the use of <mutex>. You must create a once_flag helper object. f must be static so it persists through function calls. This example uses a lambda, but you could just as easily create a regular old function above this called seedrand() or whatever and pass that in as a parameter.

Example lifted from https://en.cppreference.com/w/cpp/thread/call_once and modified to fit your program.

#include <iostream> #include <mutex> int randint(int start, int end) { static std::once_flag f; std::call_once(f, []() {srand(time(NULL)); std::cout << "Random Seeded\n"; }); return (rand() % (end - start)) + start; } int main(int argc, char** argv) { for (int i = 0; i < 10; i++) { std::cout << i << ": " << randint(1, 100) << "\n"; } } 

If you want to pass srand directly as the function, you have to pass its arguments as additional parameters. Note the lack of () after srand. You don't want to pass the RESULT of srand to call_once, you want to pass the function itself. call_once will call it for you.

static std::once_flag f; std::call_once(f, srand, time(NULL)); // notice the lack of () after srand 

Edit: std::call_once is overkill

The fact that you need to compile this with pthread is ridiculous. std::call_once should only be used to do something like this if you have multiple threads calling the same piece of code and only want it to execute once at all.

The much simpler solution would be to just use a static boolean:

int randint(int start, int end) { static bool seeded = false; if (!seeded) { srand(time(NULL)); seeded = true; } return (rand() % (end - start)) + start; } 

12 Comments

excellent answer! thanks a lot. However, I could not understand one part, why I cannot do directly std::call_once(f, srand(time(NULL))) ? I actually don't know what that []() {...} is, what should I google it as?
Here the problem message: no instance of function template "std::call_once" matches the argument list -- argument types are: (std::once_flag, void). I guess it does not like the void return type of srand(). But I cannot find what type of a return does it want
That is called a "lambda". It's an in-place function.
If you want to invoke srand, or any other function that takes arguments, you need to pass those arguments as additional paramters to the call_once function. I edited my answer with this approach.
Hey, since I asked you that, I have been dealing with it and as you just said, I figured out that I have to use it as you wrote in your answer. Thanks again btw. However, did you try the code with that formation? Because when I try it, it throws an error saying: terminate called after throwing an instance of 'std::system_error' what(): Unknown error -1 Aborted (core dumped). If you tried, can you please tell me whether it works or not in your case?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.