
The C++ community is polarized about C++11's random-number facility - DmitryNovikov
http://www.pcg-random.org/posts/ease-of-use-without-loss-of-power.html
======
cperciva
Features like this make me think that C++ is designed by people who think that
perfection is reached when there is nothing more to add. As a C developer, I
side with Antoine de Saint Exupéry.

~~~
cbsmith
Sigh... Too often that criticism is leveled at C++ without an understanding of
the terrain.

I don't think C developers should be sitting on a high horse on this one.

C represents a pretty good example of the problem. Almost every program that
relies upon the standard C runtime's random functions has a flawed random
distribution, so any correct program completely bypasses that infrastructure
and/or has a ton of additional code/complexity layered on top of it.

That open source basically festered until the C++11 <random> proposal was
accepted. The chief proponents of that proposal were, of course, those with
the most sophisticated needs & understanding for random functions, and the
proposal reflects that. So, the problems with that proposal are arguably a
consequence of the flaws in the original C standard.

What remains to be done is to harmonize that proposal with something that
makes sense to less sophisticated users, who nonetheless have reached the
point where their appreciate the problems with C's random functions.

~~~
cperciva
_Almost every program that relies upon the standard C runtime 's random
functions has a flawed random distribution_

Right, and that function is a mistake in the C standard. It should have been
omitted entirely.

~~~
cbsmith
That would have messed with C++'s goal of providing compatibility for C code.

Let's assume things had proceeded as you suggest though. We'd still not have a
good solution for random number generation until the C++11 standard came out,
and so we'd still have all the forces in place that gave rise to it and to the
current mess.

~~~
cperciva
You misunderstand me. I think random(3) should have been omitted from the _C_
standard.

~~~
pcwalton
What happens if you don't provide sensible, easy-to-use built-in
implementations of things is that a diverse, bewildering ecosystem of
different options tends to arise, confusing programmers who just want to get
their job done and leading to a high probability of them picking the wrong
thing.

See, for example, crypto before NaCl came around.

(NB: I'm not defending either this C++ standard or random(3).)

~~~
marssaxman
I thought NaCl was something related to browser plugins. What is the
connection with crypto?

~~~
ori_b
Name collisions: [http://nacl.cr.yp.to/](http://nacl.cr.yp.to/)

Although, I've never actually seen it used in the wild.

~~~
cpach
Threema use it. (I don’t know if they use it in a sane way though.)

~~~
orange_utha
They do. There's an audit that confirms it, and you can use Validation Logging
to verify it yourself:
[https://threema.ch/validation/](https://threema.ch/validation/)

------
santaclaus
I wish they had mandated the algorithms used in the distributions. Even with
the same generator initialized with the same seed, the normal distribution,
for example, will give different results across platforms. At least the
results of the generators are consistent across platforms.

~~~
Someone
Is that feasible for distributions over the reals across CPU architectures or
maybe even revisions? FPUs typically do not compute the best possible result
for floating point operations.

Also, instructions like 'estimate one over square root' have multiple
'correct' answers.

Edit:
[https://www-01.ibm.com/support/knowledgecenter/#!/ssw_aix_71...](https://www-01.ibm.com/support/knowledgecenter/#!/ssw_aix_71/com.ibm.aix.alangref/idalangref_frsqrte_instrs.htm)
shows things are worse:

"The estimate placed into register FRT is correct to a precision of one part
in 32 of the reciprocal of the square root of FRB. The value placed in FRT may
vary between implementations _and between different executions on the same
implementation._ "

~~~
api_or_ipa
Is this an indication of a randomly seeded Newtown's method?

~~~
Someone
But why would they? My guess would be that they don't bother to clear a carry
flag or are computing the estimate using a few extra significant bits, and do
not bother to initialize those at start, but that's 100% guess. I know very
little about designing CPUs.

------
ori_b
Why not specify the algorithm for std::rand?

The specification, as far as I'm aware, gives no guarantees at all about the
algorithm used. Why not just specify a good algorithm instead of adding a new
function?

~~~
cornstalks
std::rand has global state. Specifying the algorithm doesn't fix that.

And this lets you (easily) generate more than just integers in the range [0,
INT_MAX]. std::rand doesn't have that level of convenience.

There are all sorts of inconveniences with std::rand, and it looks like this
solves the vast majority of them.

~~~
ori_b
> _std::rand has global state. Specifying the algorithm doesn 't fix that._

Adding other functions also doesn't fix std:rand. People use std::rand. They
will continue to use std::rand, unless it's removed. And even then they'll
keep using it, because implementations will add it back in for compatibility.

There's already a simple, half baked, crude random number generator. It's
possible to fix it so that it provides at least acceptable randomness, and
isn't complete junk. Doing this breaks nothing.

Why add another similar function with similar API issues?

~~~
cornstalks
What is this "similar function" with "similar API issues"?

C++11's random utilities and O'Neill's randutils aren't similar to std::rand
at all. They're totally different beasts from std::rand.

Making std::rand a decent RNG would probably make the world a better place.
I'm not disagreeing with that. But even if std::rand used a decent algorithm,
it's still a suboptimal API.

------
MereInterest
One thing that I would like to have is a common base class that can be passed
around. Often, I would like for a function orclass to be told which engine to
use, quite useful for unit testing, or for having reproducible results. As it
is, the only way to accept multiple different engines is by templating over
the engine type. This ends up requiring that every part of the code that uses
the random engine be brought into the header file, and classes need to be
templated on the engine type to store a reference to the engine.

I was kind of hoping that the `random_generator` class would be a templated
class derived from a non-templated base class, so that it could be used in
this manner. Looking over it, I can see why it doesn't, as many of the methods
are much, much more useful as templated methods, which do not interact nicely
with virtual functions.

~~~
starmole
I kind of agree! But think about performance. A fast pseudo random generator
will/should create a random number in less cycles than one virtual function
call has overhead. Also it's not hard to create your own virtual random class
if you are willing to pay the price.

------
dicroce
I like this proposal and I agree that randint is a bad idea.

~~~
cbsmith
I think there is a case to be made for doing both. The one advantage of
randint is that it makes for a convenient migration path for those relying on
std::rand() and friends.

I honestly am a bit at a loss though in terms of understanding how this
proposal makes things significantly easier for programmers.

Absent this proposal, you would write:

    
    
        std::default_random_engine e(std::random_device{});
        std::uniform_int_distribution<int> uniform_dist(1, 6);
        const int random_value = uniform_dist(e);
    

The new process basically cuts the first two lines down to one, and uses a
method call for a uniform distribution instead of creating an object for it.
Is that really _easier_?

If so, then yeah, go with the idea of an empty constructor version of engines
that will smartly seed from a random device, and add a mixin that does the
magic of mapping all the different distributions in to methods.

I'm just wondering if that is somehow missing what is actually making life
difficult for developers.

~~~
Veedrac
See the author's comments on very similar code here:

[https://www.reddit.com/r/cpp/comments/31857s/random_number_g...](https://www.reddit.com/r/cpp/comments/31857s/random_number_generation_it_might_be_harder_than/cq00h6y)

> One minor issue is that you’re using `default_random_engine`, which in some
> systems may be a LCG with a tiny 32-bit state. If so, you’ll have an RNG
> with a tiny period. That’s why Stephan recommends[1] that you explicitly use
> the Mersenne Twister. Of course, it might be something better, with more
> state.

> But what’s really wrong with it is that you use a single 32-bit integer to
> seed the RNG. If you’re using the Mersenne Twister, you’re using four bytes
> of state to try to seed 624 bytes. It’ll work, but it’s way worse than what
> the Python code does; Python uses 624 bytes of actual entropy rather than
> four bytes.

[1]:
[https://www.reddit.com/r/cpp/comments/31857s/random_number_g...](https://www.reddit.com/r/cpp/comments/31857s/random_number_generation_it_might_be_harder_than/cpz7coh)

~~~
cbsmith
I think the solution for platforms which use bad default_random_engine's is
for said platforms to stop doing that. ;-)

Seriously, the whole point of platform defaults is that they make appropriate
choices for the platform. Sure, you can define your own engine, but that's
exactly what the original API gives you...

~~~
Veedrac
You could say that about a lot of platform defaults. Sadly it's still our
responsibility to avoid the bad ones.

~~~
cbsmith
Exactly. Working around it in the standard is the wrong way to do it though.
You send what the standard requires, and maybe the bad guys are standards
compliant, but there is no point in bending over backwards to work around a
platform that is going to find a way to mess it up anyway.

------
GFK_of_xmaspast
"To the extent that anyone cares about C++11's random-number facility at all,
the C++ community is polarized between two views—one that likes it, and one
that hates it."

Isn't that almost a tautology? "People who care about X either love it or hate
it".

~~~
forrestthewoods
There's a wide spectrum between love and hate.

~~~
TillE
Yeah, and all those people probably aren't participating in online discussions
about it. I'm pretty happy with most aspects of <random>, but I don't seek out
arguments. I just use it.

~~~
lmitchell
This is basically the problem with the whole Internet though ;)

------
ww2
I do not like it because [http://stackoverflow.com/questions/18880654/why-do-
i-get-sam...](http://stackoverflow.com/questions/18880654/why-do-i-get-same-
sequence-for-everyrun-with-stdrandom-device-with-mingw-gcc4)

~~~
dragontamer
Because Microsoft implemented random_device correctly while MingW / GCC
hasn't?

Its a bug in MingW. Which isn't a big deal because Microsoft Visual Studio
Community Edition is an excellent IDE and compatible with OSS projects now.

~~~
aurhum
Could you point to the gcc bug? Note: the standard does not require a non-
deterministic random_device, at least C++11 doesn't, so the behaviour as
described in the stackoverflow link would be allowed.

~~~
comex
There are a lot of things the C and C++ standards _allow_ implementations to
do, such as making int 16 bits, using one's complement for signed integers,
(in C) only making the first 31 characters of identifiers significant, (in
C++) not allowing any identifiers longer than one character, except those in
the standard library, et cetera. This is because they are designed to be
portable to a wide variety of compilers and target devices which might have
limits that weren't envisioned at the time of writing the standard. Doesn't
mean it's a good idea to write absolutely pathological implementations for no
real reason other than laziness...

~~~
aurhum
>This is because they are designed to be portable to a wide variety of
compilers and target devices which might have limits that weren't envisioned
at the time of writing the standard.

That's not really the case here, is it? If anything the bug is in the
standard.

~~~
dragontamer
> std::random_device may be implemented in terms of an implementation-defined
> pseudo-random number engine if a non-deterministic source (e.g. a hardware
> device) is not available to the implementation.

Windows has a non-deterministic source (IE: The function CryptGenRandom).
Therefore, this is a bug in MingW's implementation. CryptGenRandom is hard to
use, but that's no excuse for MingW's developers to be lazy.

Pointing at a "mistake" in the spec when the intent of the spec is extremely
clear is laziness. Pure and simple.

