0

I have my random function generating a pseudo-random number in the range:

double Utils::randomNumber(int min, int max)
{
    assert(min < max);
    srand(time(nullptr));
    return (max - min) * ((double)rand() / RAND_MAX) + min;
}

However, when I call it in a loop, I always get the very same number, although I seed the sequence:

for (int i = 0; i < m_inputs; ++i)
{
    m_weights.push_back(Utils::randomNumber(0, 1));
}

Output:

Weights: [0.787561, 0.787561, 0.787561, 0.787561, 0.787561, 0.787561, 0.787561, 0.787561, 0.787561, 0.787561, 0.787561, 0.787561]
CuriousPan
  • 783
  • 1
  • 8
  • 14
  • 6
    `srand(time(nullptr));` should be called once per the lifetime of the *process*; not the function. It doesn't belong where you have it. Frankly, you should be using the offerings of `` anyway. – WhozCraig Jan 25 '22 at 23:55
  • @WhozCraig, alright, but is there an elegant way to do it, since I'm writing kind of a library, so I need this function to be present. – CuriousPan Jan 25 '22 at 23:56
  • You're seeding the random numbers generator from scratch every time, and because the loop is tight `time(nullptr)` doesn't get to change between iterations so you end up getting the same number. – littleadv Jan 25 '22 at 23:57
  • @CuriousPanCake you need a static variable. – pm100 Jan 25 '22 at 23:57
  • @pm100, could you elaborate on that? What kind of static variable? – CuriousPan Jan 25 '22 at 23:59
  • 1
    Not sure why you would even expose it. For all intents it looks like you want what [`std::uniform_real_distribution`](https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution) already offers. – WhozCraig Jan 25 '22 at 23:59
  • That ages old C question https://stackoverflow.com/questions/7343833/srand-why-call-it-only-once explains it in detail. in C++ one should prefer – Öö Tiib Jan 26 '22 at 00:13
  • Here is a previous question about making the refresh speed faster for https://stackoverflow.com/questions/30773914/is-it-possible-to-increase-the-refresh-speed-of-srandtimenull-in-c – Shannon Starr Jan 26 '22 at 00:16

2 Answers2

4

Seeding repeatedly with tight timings will generate the same initial result after-seed every time. If seeding once per process isn't an option due to caller locality, then you should provide an initial static-state instead. What may work for you is this:

#include <random>

double Utils::randomNumber(int min, int max)
{
    static std::mt19937 rng{ std::random_device{}() };
    std::uniform_real_distribution<double> dist(min, max);
    return dist(rng);
}

Note there is an intrinsic problem on the potential ceiling of the uniform real range, and it may be applicable to your usage (not likely, but never say never). See the notes here for more information.

CuriousPan
  • 783
  • 1
  • 8
  • 14
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • This one really helped. I will get into topic to understand more, thank you! – CuriousPan Jan 26 '22 at 00:27
  • @CuriousPanCake Glad it helped. Trust me when I tell you, compared to the legacy stone-age mechanics of `srand` and `rand`, the more you learn about, and use, the offerings in `` , the more you're going to love it. – WhozCraig Jan 26 '22 at 03:25
  • initially, there was an idea to write a library using self-made functions only (yeah, I know what most of the people think of such approach), that's why I thought of implementing my own random function too. Unfortunately, it didn't work out very vell. Previously, there were cases when I tended to reinvent "already written wheel", however, I really like it. – CuriousPan Jan 26 '22 at 09:16
2

I assume you are call randomNumber function from another function main or else.

if you declare the seed inside the function, you will reset the function. Resetting the function will make the same numbers appear several times, the same second.

Moving srand(time(nullptr)); to main function should solve the problem.

  • I have randomNumber in constructor of the object and I don't really know how many objects are going to be created. – CuriousPan Jan 26 '22 at 00:01
  • @CuriousPanCake Doesn't matter. `srand` should be called **once**. – dbush Jan 26 '22 at 00:08
  • And if you do stumble across a case where `srand` needs to be called more than once, odds are extremely high that `rand` won't produce a sequence of high enough quality to live up to your needs. – user4581301 Jan 26 '22 at 00:38