> However, because the implementation of rand is unknown, it is impossible to tell whether or not using modulus to shrink the range will result in an acceptably random sequence. The reason that this might not be the case is due to the very definition of linear congruential generators.

Using the modulus operation to transform the range of std::rand is problematic, but it isn't because of any attribute of the implementation of std::rand or of linear congruential generators.

One problem with using modulus to scale a random distribution is that it fails to preserve uniformity. For example, consider a function 'rand150' whose result is uniformly distributed on [0, 150); that is, each number in the range [0, 150) has the same probability (1/150) of being returned by any given call to rand150. Now, if you use modulus to scale to [0, 100):

x = rand150() % 100;

there are 100 possible values for x. For any value greater than or equal to 50, there is exactly one result of rand150 which could produce that value; therefore, the probability of x being that value is 1/150. But for values less than 50, there are two results of rand150 which could produce that value, giving it a probability of 2/150. Since half of the possible values of x have a probability of 1/150 each and the other half have a probability of 2/150 each (you can check that this adds up to a probability of 1), the distribution is very much nonuniform. This result does not apply just to small ranges; it applies any time you scale down the range by anything but an integer multiple, although it approaches uniformity more closely the smaller the target range is compared to the source range.

The other problem is that you can't make the range bigger. Well, you actually can— but some of your "x" values will have a probability of zero, which probably isn't what you want. Considering rand150 again, if you try to scale to [0, 300) by doing:

x = rand150() % 300;

how often do you expect to get 250?

> The common solution is to use the constant value RAND_MAX, defined with every standard library, to use the high-order bits of a random number through division rather than low-order bits with the remainder of division

I'm not sure if there's a typo in the code, but if RAND_MAX is, say, 200, then

rand() / (RAND_MAX / 100 + 1)

gives you values on [0, 66]. Probably not what you want.

> An alternative to dividing RAND_MAX by N is to force the expression to floating-point and multiply RAND_MAX by N

Mathematically, this would be a sensible way of scaling continuous uniform distributions, or at least it would be if floating-point numbers weren't so imprecise. When dealing with discrete distributions, though, this approach still has problems. For example, what if rand gives values on [0, 30) and I want values on [0, 20)? Let's see what values of rand map to, assuming perfect real numbers:

rand x
0 floor(0) = 0
1 floor(2/3) = 0
2 floor(4/3) = 1
3 floor(6/3) = 2
4 floor(8/3) = 2

Unfortunately, 1 will only be generated half as often as 0 or 2.

> Yet another alternative is to utilize the uniform_deviate function provided not too long ago

Mathematically, this is equivalent to the above. The floating point arithmetic may be very slightly different, but it will make the result worse if anything.