1

Consider this body of main:

std::srand(std::time(nullptr));
while (std::rand());

Surprisingly, I couldn't find anything, whether it be in the spec, on Google, or on this website, about whether that is well-defined. As for the spec:

N3485 § 6.5/4 [stmt.iter] says this about the condition:

[ Note: The requirements on conditions in iteration statements are described in 6.4. — end note ]

However, looking through 6.4, I saw nothing that refers to this scenario. In theory, the loop could virtually go on forever, but in practice, I usually had a run time of 5ms, with one time in all test runs being 22ms.

Is it well-defined behaviour to base the loop termination condition on a changing (pseudo)random number? If it isn't, which kind of behaviour is it?

chris
  • 60,560
  • 13
  • 143
  • 205
  • 6
    Why would this be a special case? How is this different to (for example) a loop conditioned on user input? (both are non-deterministic) – Oliver Charlesworth Jan 06 '13 at 13:21
  • @OliCharlesworth, Good point, that never occurred to me. However, where does the spec say that's valid? I reread 6.4, and maybe I'm missing something obvious, but didn't pick it up. – chris Jan 06 '13 at 13:23
  • 4
    But I'm not sure why the standard would need to address this specifically... – Oliver Charlesworth Jan 06 '13 at 13:26
  • @OliCharlesworth, You're right. It's becoming clear what you mean. I'm not sure how my mind got so contrived while writing this. – chris Jan 06 '13 at 13:28
  • Where does it say that while (1); is not well-defined, btw? (I looked at the standard but could not find remarks about loop termination). – Chris Jan 06 '13 at 13:38
  • @Chris, It is well-defined. It's an infinite loop. You might be misled from what I wrote in the post. – chris Jan 06 '13 at 13:39
  • @Chris I must have misunderstood your question, if it was not about termination. (Btw, I wonder if non-unique usernames in SO are a feature or a bug right now ;-) – Chris Jan 06 '13 at 13:47
  • @Chris, You can have the same user name. Just look on the user search for how many chris and Chris usernames are there. Anyway, it was, but the answer is such that why did I ask in the first place? It's more common sense than it is a language question, really, and I was too braindead to notice until that got pointed out. For what it's worth, I could change the question to "Is it bedtime yet?" – chris Jan 06 '13 at 13:51
  • My thoughts on this: Either `rand()` is a deterministic function, in which case you can compute whether or not it eventually returns zero and how long it takes, or you're reading from a true-randomness source, which requires a system call and thus makes the loop behaviour OK. – Kerrek SB Jan 06 '13 at 14:00

5 Answers5

7

std::rand() will be called at each iteration, then the loop will go on or not depending on its return value.

There is no reason to have any undefined behavior here.

It's not different from doing something like this

while (my_vector.empty());

Why do you think this case would be special?

cmc
  • 2,061
  • 1
  • 19
  • 18
  • That's another good point. I was getting hung up on the fact that it could be an infinite loop, or not, but both are simply just doing their well-defined jobs. – chris Jan 06 '13 at 13:31
  • @chris: It will never be an infinite loop. It is effectively guaranteed to terminate _eventually_ (even if this takes several billion years), unlike `while (true)`. – Lightness Races in Orbit Jan 06 '13 at 14:42
  • @LightnessRacesinOrbit It could be an infinite loop, both theoretically and practically. Theoretically there's an infinitesimally small probability given a perfect RNG, but that's not the same as zero. Practically, `rand()` is a pseudo RNG that generates a finite cycle of values, and that cycle may not contain 0. – bames53 Jan 07 '13 at 16:08
  • @bames53: "Effectively" so I count infintessimal as negligible. If `rand()` can never evaluate to 0 though, then that changes things rather. If that's the case then [the loop invokes UB](http://stackoverflow.com/q/5905155/560648) as it may never terminate and, in any compliant program, the compiler must be able to assume that a loop will terminate. But are you sure the cycle cannot contain 0? – Lightness Races in Orbit Jan 07 '13 at 16:28
3

The behavior of

while (std::rand());

is, surely, well defined. That means, it changes the state of the built-in pseudorandom number generator to some state where it returns 0.

However, because the compiler may assume this loop will eventually terminate (by [intro.multithread]/24), it may be the case you either won't perceive the delay, or that some visible effect from the program after it will take place before the delay (if you have a frightfully clever compiler).

jpalecek
  • 47,058
  • 7
  • 102
  • 144
1

Whilst I'm sure we have covered the case of "is this legal", I'm not sure it's a very good idea to use this particular method to wait a random [1] amount of time.

I would think that using something along the lines of

int delay = constant + rand() * factor;
usleep(delay);

would be a much better choice. It reduces the CPU load, and it gives you a defined range - there is no guarantee that rand() will give you a zero within the first gazillion calls, so the delay may well vary quite dramatically.

[1] Assuming srand() is given a suitably varying number - I'm not sure "time()" is the best way to achieve that. It's fine if you re-initialize once a day, but if you have code that starts several times in the same second, they all get the same seed.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
1

To add to the other answers, the reason for the clause in the standard allowing the compiler to assume that any loop will terminate is not to make infinite loops undefined, but to allow optimizations to take place even in situations where a compiler can't determine if a loop will terminate.

For instance, in this situation

while(rand()) f();

if the compiler could determine that neither rand nor f have any side effects, the compiler could eliminate the entire loop, even if it couldn't prove that rand will eventually return 0.

Dirk Holsopple
  • 8,731
  • 1
  • 24
  • 37
  • I'm not sure why the standard would have to speak in terms of undefined behavior (WRT endless loops), rather that simply saying that a compiler is free to defer the execution of any piece of code until its first observable effect, and that the time required to execute a piece of code, even if infinite, is not considered to be an "observable effect". If a variable is set in a loop which may or may not exit and has no other side-effects, and if other code may or may not read the variable, the compiler would be free to defer execution of the code unless or until that variable is needed. – supercat Jan 12 '13 at 03:14
  • If it turns out that the variable in question is never needed, the effect would be that the execution of the endless loop might be deferred until everything else happened first. No problem. – supercat Jan 12 '13 at 03:18
-1

In this case initialization of srand is always the same, so the behavior of the while is is the same at each execution. Try to put in time some random data and you can see the change in execution time.

Mihai8
  • 3,113
  • 1
  • 21
  • 31
  • 2
    I hate to say it, but my mental state is still enough to say that the behaviour will differ every new second that the program is run. `srand` is called once with a seed that keeps going up, so it can only be the same throughout executions until a second passes. – chris Jan 06 '13 at 13:37
  • Indeed srand () will give different results on each execution of it. However from the same root sequence of random numbers will be the same. Loop will be run until srand () will generate 0. This means that during the execution of the while loop will be the same if root of the sequence random number generation is constant. – Mihai8 Jan 06 '13 at 13:54