0

My first attempt at creating a header file. The solution is nonsense and nothing more than practice. It receives two numbers from the main file and is supposed to return a random entry from the vector. When I call it from a loop in the main file, it increments by 3 instead of randomly. (Diagnosed by returning the value of getEntry.) The Randomizer code works correctly if I pull it out of the header file and run it directly as a program.

int RandomNumber::Randomizer(int a, int b){
    std::vector < int > vecArray{};
    int range = (b - a) + 1;

    time_t nTime;
    srand((unsigned)time(&nTime));

    for (int i = a-1; i < b+1; i++) {
        vecArray.push_back(i);
    }

    int getEntry = rand() % range + 1;

    int returnValue = vecArray[getEntry];
    vecArray.clear();

    return returnValue;
}

From what I read, header files should generally not contain function and variable definitions. I suspect Rand, being a function, is the source of the problem.

How, if possible, can I get my header file to create random numbers?

Mr. Coz
  • 25
  • 11
  • 6
    You should not run `srand((unsigned)time(&nTime));` more than once per second. – mch Dec 15 '20 at 15:17
  • In my main I have the following: int numbOfMilliSec = 2000; std::this_thread::sleep_for(std::chrono::milliseconds(numbOfMilliSec)); – Mr. Coz Dec 15 '20 at 15:21
  • Also, thank you for letting my know about not running it more than once per second. That explains quarky things I've had with other programs. – Mr. Coz Dec 15 '20 at 15:23
  • 6
    You should usually not run `srand()` more than once per program execution. Execute it once when the program starts - but use a better seed if you want it to be a little better. Best would be to use the new random classes and functions in `` [example](https://stackoverflow.com/a/64491544/7582247) – Ted Lyngmo Dec 15 '20 at 15:25
  • I will give the new random classes and functions in a try in a different test (unless it is needed to make this one work). I appreciate the pointer. As for running srand() more than once per program execution, is this more of an opinion and/or best practice or will it create issues other than excessive program cycles? – Mr. Coz Dec 15 '20 at 15:39
  • Well ... it's an educated opinion. :-) Every call to `srand()` re-seeds the random number generator which is often expensive (in terms of time) and it's also pointless - unless you are testing the random number generator itself. Furthermore: Seeding it with the same number (as in using `time` to seed it more than once the same second) causes it to generate the same numbers from the start again. Start two programs at the same time and they will generate the same numbers for example. – Ted Lyngmo Dec 15 '20 at 15:44
  • If you are sticking with `rand()` you can still seed it better by including `` and do `std::srand(std::random_device{}());` right at the start of your program - then do not call `srand()` again. – Ted Lyngmo Dec 15 '20 at 15:49
  • @TedLyngmo on what platfom canonical random number generator is expensive? It's usually very simple and predictable unless seeded: https://stackoverflow.com/questions/18969783/how-can-i-get-the-sourcecode-for-rand-c – Swift - Friday Pie Dec 15 '20 at 21:17
  • @Swift-FridayPie I'm talking about seeding: "_Every call to `srand()` re-seeds the random number generator which is often expensive (in terms of time)_". Even if there are implementations that seeds relatively quickly - it's in most cases totally pointless. – Ted Lyngmo Dec 15 '20 at 21:19
  • @Mr.Coz You asked if it's more of an opinion that one shouldn't seed more than once. To answer that properly, I made this [quick-bench](https://quick-bench.com/q/CRNhryNKRs3GxirKWv9eZH3hk7A) graph to show you the cost of re-seeding in one common implementation. When the cost is this high, I would indeed call it wrong to keep re-seeding. – Ted Lyngmo Dec 15 '20 at 21:48

4 Answers4

2
void random(){
    double rangeMin = 1;
    double rangeMax = 10;
    size_t numSamples = 10;

    thread_local std::mt19937 mt(std::random_device{}());
    std::uniform_real_distribution<double> dist(rangeMin, rangeMax);

    for (size_t i = 1; i <= numSamples; ++i) {
        std::cout << dist(mt) << std::endl;
    }
}

This method will give you the opportunity to generate random numbers, between two numbers this method you have to include random

SYZYGY
  • 75
  • 10
  • you should try `using namespace std;` to save time. I mean, if you did not put that because you only put a portion of the code, then nevermind my comment. – Skyy Civil Dec 15 '20 at 19:25
  • @SkyyCivil actually this code snippet is part of one of my project. I just delete the unnecessary part of the code – SYZYGY Dec 15 '20 at 19:57
  • @SkyyCivil There are four `std::`'s in the function (I don't count `std::endl` since that should be `'\n'` anyway). Four `std::`'s are equal to `using namespace std;` in length and doing `using namespace std;` is rarely a good idea outside function scope. It's definitely a big no-no to put it in the global scope in a header file. – Ted Lyngmo Dec 15 '20 at 20:49
0

There are many cases where you will optate to engender a desultory number. There are genuinely two functions you will require to ken about arbitrary number generation. The first is rand(), this function will only return a pseudo desultory number. The way to fine-tune this is to first call the srand() function.

Here is an example:

#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;
 
int main () {
   int i,j;
 
   
   srand( (unsigned)time( NULL ) );

   for( i = 0; i < 10; i++ ) {
      
      j = rand();
      cout <<" Random Number : " << j << endl;
   }

   return 0;
}

Using srand( (unsigned)time( NULL ) ); Instead of using your own value use NULL for the default setting. You can also go here for more info.

I hope I answered your question! Have a nice day!

Skyy Civil
  • 63
  • 8
  • Thanks for the suggestion, but my issue has to do with creating random numbers in a header file. While you solution (just like mine) works in main, it gives me the same results when placed in the header file. – Mr. Coz Dec 15 '20 at 15:56
  • NP, at least you are trying to contribute. :) – Mr. Coz Dec 15 '20 at 16:02
  • Skyy: Since you recommend people using `using namespace std;` I think you should read [Why is `using namespace std;` considered bad practice?](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) – Ted Lyngmo Dec 16 '20 at 20:20
0

Ted Lyngmo gave me the idea that fixed the problem. Using random appears to work correctly in a header file.

I removed/changed the following:

time_t nTime;
srand((unsigned)time(&nTime));
int getEntry = rand() % range + 1;

and replaced them with:

std::random_device rd;
std::mt19937 gen(rd());
int getEntry = gen() % range + 1;

Issue resolved. Thank you everybody for your suggestions and comments!

Mr. Coz
  • 25
  • 11
  • You're still doing a lot of unnecessary work. Any random number generator, whether it's `rand` or something else, should only be initialized once. It doesn't work properly if you're continually reinitializing it. P.S. don't use `%` to bind your number to a specific range, there's functions in `random` to do that. – Mark Ransom Dec 15 '20 at 17:06
  • The purpose was not to specifically to create random numbers. The exercise was to build a header file. My first header file is now under my belt. – Mr. Coz Dec 15 '20 at 17:11
  • 1
    That is probably you are not implement the ifndef prepocessor. For headfile, you have #ifndef __my_randomize__ #define __my_randomize__ .....#endif (in the last line. This prevent the head to be executed again. – ytlu Dec 15 '20 at 17:31
  • That's no excuse for learning bad habits. In fact you can use it as a learning experience, knowing what things shouldn't go in header files. – Mark Ransom Dec 15 '20 at 17:31
  • @ytlu that doesn't prevent the code from *executing* more than once, only from being *defined* more than once. If you define more than once you'll probably get a compile error. – Mark Ransom Dec 15 '20 at 17:33
  • @MarkRansom yes. My statement is not accurate enough. – ytlu Dec 15 '20 at 17:35
  • @ytlu – I didn't understand what you were referring to when you mentioned #ifndef and # ydefine. I just read about them; "header guard (also called an include guard)." As you suggested, not having them could be what is causing the issue. I rolled back my code and tried what you suggested. Turns out I have #include in the header code file. If I comment out time.h, the program works as expected. I still need to keep working on header guards since it appears it will be important when I start creating real code. – Mr. Coz Dec 15 '20 at 21:12
  • @Mr.Coz I am glad to be helping. You may open any header, and learn from it. The logic command in the head prevent the header to be compiled twice. It is not possible that time.h casues you trouble. You may include any header without using it, it won't bring any effect to you program, simply make your code larger. – ytlu Dec 16 '20 at 14:46
0

As an experiment, I remove the vector and focus on the randomizer `srand(T)`, where `T` is the system time `volatile time_t T = time(NULL)`. We then found that system is NOT changed during the program running (execution simply too fast).

The function `rand()` generates a pesudo-random integer using confluent rnadom generator, basically multiply the seed by another larger unsigned integer and truncated to the finite bits of `seed`. The randomizer `srand(T)` is used to initialize the seed using system time, or any number `srand(12345);` . A seed gives a fixed sequence of random number. Without calling `srand(T)`, the seed is determined by the system initial memory gabage. The seed is then changed in every generating `rand()`.

In your code, you issue randomizer `srand(T)` reset the seed to the system time in every run. But the system time didn't changed, Thus, you are reseting the `seed` to a same number.

Run this test.

#include <cstdlib>
#include <iostream>
#include <ctime>
int Randomizer(int a, int b){
    volatile time_t T = time(NULL);
    std::cout << "time = " << T << std::endl;
    srand(T);
    std::cout << "rand() = " << rand() << std::endl;
    return rand();
}
int main()
{
   int n1 = 1, n2 = 8;
   for(int i=0; i<5; ++i)
   {
        std::cout << Randomizer(n1, n2) << std::endl;
   }
}

The seed is reset to the system time, which is not change during execution. Thus It renders the same random number.

$ ./a.exe
time = 1608049336
rand() = 9468
15874
time = 1608049336
rand() = 9468
15874
time = 1608049336
rand() = 9468
15874
time = 1608049336
rand() = 9468
15874
time = 1608049336
rand() = 9468
15874

In order to see the change of system time, we add a pause in the main():

int main()
{
    int n1 = 1, n2 = 8;
    for(int i=0; i<5; ++i)
    {
        std::cout << Randomizer(n1, n2) << std::endl;
        system("pause");
    }
}

We can observe the system time moving on...

$ ./a.exe
time = 1608050805
rand() = 14265
11107
Press any key to continue . . .

time = 1608050809
rand() = 14279
21332
Press any key to continue . . .

time = 1608050815
rand() = 14298
20287
Press any key to continue . . .

Because system time is not much different, the first generation of confluent sequence rand() is also rather closed, but the continue sequence of numbers will be "seemingly" random. The principle for confluent random generator is that once after set the seed don't change it. Until you are working for another series of random set. Therefore, put the srand(T) funtcion just once in the main() or somewhere that executed only once.

int main()
{
    srand(time(NULL)); // >>>> just for this once  <<<< 
    int n1 = 1, n2 = 8;
    for(int i=0; i<5; ++i)
   {
        std::cout << Randomizer(n1, n2) << std::endl;
   }
}
ytlu
  • 412
  • 4
  • 9
  • My code worked using srand in a function, but would not work when put in a header file. Each call to the header file used numbOfMilliSec = 2000 in a sleep_for function. I have a feeling the issue was compiler related. Changing to use #include resolved the issue and the header file works as expected. – Mr. Coz Dec 15 '20 at 17:19
  • Yes. You feel comfortable is the most important priority. – ytlu Dec 15 '20 at 17:23
  • @Mr.Coz But it is due to the same reason, You are not using Randomizer in you function. The head file run and randomize the seed only once. – ytlu Dec 15 '20 at 17:27