{"id":1325,"date":"2015-12-09T21:58:33","date_gmt":"2015-12-10T05:58:33","guid":{"rendered":"http:\/\/www.elbeno.com\/blog\/?p=1325"},"modified":"2015-12-09T23:04:36","modified_gmt":"2015-12-10T07:04:36","slug":"lameness-explained","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=1325","title":{"rendered":"Lameness Explained"},"content":{"rendered":"<p>OK, more than one person wanted explanations of <a href=\"https:\/\/www.elbeno.com\/blog\/?p=1318\">The C++ &lt;random&gt; Lame List<\/a>, so here are some of my thoughts, if only to save people searching elsewhere.<\/p>\n<ol>\n<li>Calling <code>rand()<\/code> is lame because it&#8217;s an LCG with horrible randomness properties, and we can do better. And if you&#8217;re not calling <code>rand()<\/code>, there&#8217;s no reason to call <code>srand()<\/code>.<\/li>\n<li>Using <code>time(NULL)<\/code> to seed your RNG is lame because it doesn&#8217;t have enough entropy. It&#8217;s only at a second resolution, so in particular, starting multiple processes (e.g. a bringing up bunch of servers) at the same time is likely to seed them all the same.<\/li>\n<li>No, <code>rand()<\/code> isn&#8217;t good enough even for simple uses, and <a href=\"https:\/\/www.elbeno.com\/blog\/?p=1081\">it&#8217;s easy to do the right thing these days<\/a>. The lower order bits of <code>rand()<\/code>&#8216;s output are particularly non-random, and odds are that if you&#8217;re using <code>rand()<\/code> you&#8217;re also using <code>%<\/code> to get a number in the right range. See item 6.<\/li>\n<li>In C++14 <code>random_shuffle()<\/code> is deprecated, and it&#8217;s removed in C++17, which ought to be reason enough. If you need more reason, one version of it is inconvenient to use properly (it uses a Fisher-Yates\/Knuth shuffle so takes an RNG that has to return random results in a shifting range) and the other version of it can use <code>rand()<\/code> under the hood. See item 1.<\/li>\n<li><code>default_random_engine<\/code> is implementation-defined, but in practice it&#8217;s going to be one of the standard generators, so why not just be explicit and cross-platform-safe (hint: item 10)?. <a href=\"https:\/\/www.reddit.com\/r\/cpp\/comments\/3vtavn\/stl_fixes_in_vs_2015_update_1\/cxqwys6\">Microsoft&#8217;s default is good, but libc++ and libstdc++ both use LCGs as their default at the moment<\/a>. So not much better than <code>rand()<\/code>.<\/li>\n<li>It is overwhelmingly likely that whatever RNG you use, it will output something in a power-of-two range. Using <code>%<\/code> to get this into the right range probably introduces bias. Re item 3, consider a canonical simple use: rolling a d6. No power of two is divisible by 6, so inevitably, <code>%<\/code> will bias the result. Use a distribution instead. <a href=\"https:\/\/twitter.com\/StephanTLavavej\">STL<\/a> (and others) have poured a lot of time into making sure they aren&#8217;t biased.<\/li>\n<li><code>random_device<\/code> is standard, easy to use, and should be high quality randomness. It may not be very well-performing, which is why you probably want to use it for seeding only. But you do want to use it (mod item 8).<\/li>\n<li>Just know your platform. It might be fine in desktop-land, but <code>random_device<\/code> isn&#8217;t always great. It&#8217;s supposed to be nondeterministic and hardware based if that&#8217;s available&#8230; trust but verify, as they say.<\/li>\n<li>Not handling exceptions is lame. And will bite you. I know this from experience with <code>random_device<\/code> specifically.<\/li>\n<li>The Mersenne twisters are simply the best randomness currently available in the standard.<\/li>\n<li>Putting <code>mt19937<\/code> on the stack: a) it&#8217;s large (~2.5k) and b) you&#8217;re going to be initializing it each time through. So probably not the best. See item 17 for an alternative.<\/li>\n<li>You&#8217;re just throwing away entropy if you don&#8217;t seed the generator&#8217;s entire state. (This is very common, though.)<\/li>\n<li>Simply, <code>uniform_int_distribution<\/code> works on a closed interval (as it must &#8211; otherwise it couldn&#8217;t produce the maximum representable value for the given integral type). If you forget this, it&#8217;s a bug in your code &#8211; and maybe one that takes a while to get noticed. Not good.<\/li>\n<li>Forgetting <code>ref()<\/code> around your generator means you&#8217;re copying the state, which means you&#8217;re probably <a href=\"http:\/\/stackoverflow.com\/questions\/27365422\/how-to-avoid-same-random-results-using-stdmt19937\">not advancing the generator<\/a> <a href=\"http:\/\/stackoverflow.com\/questions\/29586192\/c-stdgenerate-function-always-gives-same-values\">like you thought you were<\/a>.<\/li>\n<li><code>seed_seq<\/code> is <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/numeric\/random\/seed_seq\">designed to seed RNGs<\/a>, it&#8217;s that simple. It tries to protect against poor-quality data from <code>random_device<\/code> or whatever variable-quality source of entropy you have.<\/li>\n<li>Not considering thread safety is always lame. Threads have been a thing for quite a while now.<\/li>\n<li><code>thread_local<\/code> is an easy way to get &#8220;free&#8221; thread safety for your generators.<\/li>\n<li>You should be using a Mersenne twister (item 10) so just use the right thing for <code>max()<\/code>. Job done.<\/li>\n<\/ol>\n<p>If you want more, see <a href=\"https:\/\/channel9.msdn.com\/Events\/GoingNative\/2013\/rand-Considered-Harmful\"><code>rand()<\/code> Considered Harmful<\/a> (a talk by Stephan T Lavavej), or <a href=\"http:\/\/cpp.indi.frih.net\/blog\/2014\/12\/the-bell-has-tolled-for-rand\/\">The bell has tolled for <code>rand()<\/code><\/a> (from the Explicit C++ blog), or see Melissa O&#8217;Neill&#8217;s <a href=\"https:\/\/www.reddit.com\/comments\/2momvr\">Reddit thread<\/a>, her <a href=\"https:\/\/www.youtube.com\/watch?v=45Oet5qjlms\">talk on PCG<\/a>, and the <a href=\"http:\/\/www.pcg-random.org\/\">associated website<\/a>.<\/p>\n<p>And of course, <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/numeric\/random\">cppreference.com<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>OK, more than one person wanted explanations of The C++ &lt;random&gt; Lame List, so here are some of my thoughts, if only to save people searching elsewhere. Calling rand() is lame because it&#8217;s an LCG with horrible randomness properties, and we can do better. And if you&#8217;re not calling rand(),&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22],"tags":[],"class_list":["post-1325","post","type-post","status-publish","format-standard","hentry","category-cpp"],"_links":{"self":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1325","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1325"}],"version-history":[{"count":17,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1325\/revisions"}],"predecessor-version":[{"id":1342,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1325\/revisions\/1342"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1325"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1325"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1325"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}