4 ms·
I like this proposal and I agree that randint is a bad idea.
by dicroce 11y ago
I like this proposal and I agree that randint is a bad idea.
- cbsmith 11y agoI 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.
- deleted 11y ago[deleted]
- com2kid 11y agoThe current way separates out what will be gotten back from the engine from the actual invocation. In comparison, the proposal lets me look at one line and know what will be returned: rng.uniform(1,17) I know exactly what to expect. Compare that to: uniform_dist(e); Unless the variable is named very well ("UniformDistOneToSix"?), I don't know what that line does. Not to mention, what if I want to roll a bunch of numbers in a row? Do I create all the different distributions that I may ever need ahead of time? If I don't know what all random ranges I'll need, I guess I can just create them on the stack as needed, instantiating objects willy nilly. Eew.
- cbsmith 11y agoI'd just call it "from_one_to_six". I guess if it is really a mystery, you could just always do: std::uniform_int_distribution<int>{1, 6}(e); ...and use some typedefs to avoid it being quite so verbose. I'm not sure I grok the bunch of numbers in a row scenario. Usually in that case I'd imagine you'd want to create a bunch of numbers with a consistent distribution, which is exactly why you have the structure you want. If not, you can always create new distributions in an ad hoc fashion (exactly why it is good that the parameters for a distribution are NOT template parameters). Instantiating distributions isn't costing you anything here. It's just a transient struct with a handful of fields... though if you use it for more than one call, it might somehow be more efficient (doubtful, but conceivable). In practice, you pretty much always end up with something that holds the engine inside it, and you can always decorate it with methods like: int roll_die(){ return std::uniform_int_distribution<int>{1, 6}(e); } ...or alternatively: template <typename T> T uniform(const T begin, const T end) { return std::uniform_int_distribution<T>{begin, end}(e); }
- Veedrac 11y agoSee the author's comments on very similar code here: https://www.reddit.com/r/cpp/comments/31857s/random_number_generation_it_might_be_harder_than/cq00h6y https://www.reddit.com/r/cpp/comments/31857s/random_number_g... > 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_generation_it_might_be_harder_than/cpz7coh https://www.reddit.com/r/cpp/comments/31857s/random_number_g...
- cbsmith 11y agoI 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 11y agoYou could say that about a lot of platform defaults. Sadly it's still our responsibility to avoid the bad ones.
- cbsmith 11y agoExactly. 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.
- cbsmith 11y agoNow I finally get it. C++11's seed sequences are not compatible with std::random_device. I'd been using the pre-C++11 boost::random and hadn't realized there was this subtle difference. That is super annoying.