![Page 1: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/1.jpg)
Version 1.1 - September 5, 2013 1
rand() Considered HarmfulStephan T. Lavavej ("Steh-fin Lah-wah-wade")Senior Developer - Visual C++ [email protected]
![Page 2: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/2.jpg)
2
What's Wrong With This Code?#include <stdio.h>#include <stdlib.h>#include <time.h>int main() { srand(time(NULL)); for (int i = 0; i < 16; ++i) { printf("%d ", rand() % 100); } printf("\n");}
![Page 3: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/3.jpg)
3
What's Right With This Code?#include <stdio.h>#include <stdlib.h>#include <time.h>int main() { srand(time(NULL)); for (int i = 0; i < 16; ++i) { printf("%d ", rand() % 100); } printf("\n");}
All required headers are included!
All included headers are required!
Headers are sorted!
One True Brace Style!
Unnecessary argc, argv, return 0; omitted!
%d is correct for int!
![Page 4: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/4.jpg)
4
What's Wrong With This Code?#include <stdio.h>#include <stdlib.h>#include <time.h>int main() { srand(time(NULL)); for (int i = 0; i < 16; ++i) { printf("%d ", rand() % 100); } printf("\n");}
![Page 5: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/5.jpg)
5
What's Wrong With This Code?#include <stdio.h>#include <stdlib.h>#include <time.h>int main() { srand(time(NULL)); for (int i = 0; i < 16; ++i) { printf("%d ", rand() % 100); } printf("\n");}
ABOMINATION!
![Page 6: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/6.jpg)
6
What's Wrong With This Code?#include <stdio.h>#include <stdlib.h>#include <time.h>int main() { srand(time(NULL)); for (int i = 0; i < 16; ++i) { printf("%d ", rand() % 100); } printf("\n");}
ABOMINATION!
Frequency: 1 Hz!
![Page 7: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/7.jpg)
7
What's Wrong With This Code?#include <stdio.h>#include <stdlib.h>#include <time.h>int main() { srand(time(NULL)); for (int i = 0; i < 16; ++i) { printf("%d ", rand() % 100); } printf("\n");}
ABOMINATION!
Frequency: 1 Hz!
warning C4244:
'argument' : conversion
from 'time_t' to 'unsigned
int', possible loss
of data
32-bit seed!
![Page 8: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/8.jpg)
8
What's Wrong With This Code?#include <stdio.h>#include <stdlib.h>#include <time.h>int main() { srand(time(NULL)); for (int i = 0; i < 16; ++i) { printf("%d ", rand() % 100); } printf("\n");}
ABOMINATION!
Frequency: 1 Hz!
warning C4244:
'argument' : conversion
from 'time_t' to 'unsigned
int', possible loss
of data
32-bit seed!
Range: [0, 32767]
Linear congruential low quality!
![Page 9: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/9.jpg)
9
What's Wrong With This Code?#include <stdio.h>#include <stdlib.h>#include <time.h>int main() { srand(time(NULL)); for (int i = 0; i < 16; ++i) { printf("%d ", rand() % 100); } printf("\n");}
ABOMINATION!
Frequency: 1 Hz!
warning C4244:
'argument' : conversion
from 'time_t' to 'unsigned
int', possible loss
of data
32-bit seed!
Range: [0, 32767]
Linear congruential low quality!
Non-uniform distribution!
![Page 10: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/10.jpg)
10
Modulo Non-Uniform Distributionint src = rand(); // Assume uniform [0, 32767]int dst = src % 100; // Non-uniform [0, 99]// [0, 99] src [0, 99] dst// [100, 199] src [0, 99] dst// ...// [32700, 32767] src [0, 67] dst• This is modulo's fault, not rand()'s• Trigger: input range isn't exact multiple of output range
![Page 11: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/11.jpg)
11
Floating-Point Treacheryint src = rand(); // Assume uniform [0, 32767]int dst = static_cast<int>( // As seen on (src * 1.0 / RAND_MAX) * 99 // StackOverflow); // Hilariously non-uniform [0, 99]• Only one input produces the output 99:static_cast<int>((32765 * 1.0 / 32767) * 99) == 98static_cast<int>((32766 * 1.0 / 32767) * 99) == 98static_cast<int>((32767 * 1.0 / 32767) * 99) == 99
![Page 12: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/12.jpg)
12
Floating-Point Double Treacheryint src = rand(); // Assume uniform [0, 32767]int dst = static_cast<int>( (src * 1.0 / (RAND_MAX + 1)) * 100); // Subtly non-uniform [0, 99]• Less likely outputs (327/32768 vs. 328/32768):3, 6, 9, 12, 15, 18, 21, 24, 28, 31, 34, 37, 40, 43, 46, 49, 53, 56, 59, 62, 65, 68, 71, 74, 78, 81, 84, 87, 90, 93, 96, 99• Same problem as src % 100• Nothing can uniformly map 32768 inputs to 100 outputs
![Page 13: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/13.jpg)
13
Floating-Point Triple Treachery• What if the input is [0, 232) or [0, 264)?• Non-uniformity is reduced, but not eliminated, when the
input is much larger than the output
• What if IEEE runs out of bits?• Example: [0, 264) input [0, 1018 ≈ 259.8) output• double has only 53 bits of significand precision
• Say you have a problem, so you use floating-point• Now you have 2.000001 problems
• DO NOT MESS WITH FLOATING-POINT
![Page 14: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/14.jpg)
14
<random> URNGs(Uniform Random Number Generators)
• Engine templates:• linear_congruential_engine• mersenne_twister_engine• subtract_with_carry_engine
• Engine adaptor templates:• discard_block_engine• independent_bits_engine• shuffle_order_engine
• Non-deterministic:• random_device
• Engine (adaptor) typedefs:• minstd_rand0• minstd_rand• mt19937• mt19937_64• ranlux24_base• ranlux48_base• ranlux24• ranlux48• knuth_b• default_random_engine
![Page 15: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/15.jpg)
15
<random> Distributions• Uniform distributions
• uniform_int_distribution• uniform_real_distribution
• Poisson distributions• poisson_distribution• exponential_distribution• gamma_distribution• weibull_distribution• extreme_value_distribution
• Sampling distributions• discrete_distribution• piecewise_constant_distribution• piecewise_linear_distribution
• Bernoulli distributions• bernoulli_distribution• binomial_distribution• geometric_distribution• negative_binomial_distribution
• Normal distributions• normal_distribution• lognormal_distribution• chi_squared_distribution• cauchy_distribution• fisher_f_distribution• student_t_distribution
![Page 16: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/16.jpg)
16
Hello, "Random" World!#include <iostream>#include <random>int main() { std::mt19937 mt(1729); std::uniform_int_distribution<int> dist(0, 99); for (int i = 0; i < 16; ++i) { std::cout << dist(mt) << " "; } std::cout << std::endl;}
![Page 17: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/17.jpg)
17
Hello, "Random" World!#include <iostream>#include <random>int main() { std::mt19937 mt(1729); std::uniform_int_distribution<int> dist(0, 99); for (int i = 0; i < 16; ++i) { std::cout << dist(mt) << " "; } std::cout << std::endl;}
Deterministic 32-bit seed
![Page 18: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/18.jpg)
18
Hello, "Random" World!#include <iostream>#include <random>int main() { std::mt19937 mt(1729); std::uniform_int_distribution<int> dist(0, 99); for (int i = 0; i < 16; ++i) { std::cout << dist(mt) << " "; } std::cout << std::endl;}
Deterministic 32-bit seed
Engine: [0, 232)
![Page 19: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/19.jpg)
19
Hello, "Random" World!#include <iostream>#include <random>int main() { std::mt19937 mt(1729); std::uniform_int_distribution<int> dist(0, 99); for (int i = 0; i < 16; ++i) { std::cout << dist(mt) << " "; } std::cout << std::endl;}
Deterministic 32-bit seed
Engine: [0, 232)
Distribution: [0, 99]
![Page 20: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/20.jpg)
20
Hello, "Random" World!#include <iostream>#include <random>int main() { std::mt19937 mt(1729); std::uniform_int_distribution<int> dist(0, 99); for (int i = 0; i < 16; ++i) { std::cout << dist(mt) << " "; } std::cout << std::endl;}
Deterministic 32-bit seed
Engine: [0, 232)
Distribution: [0, 99]
Note: [inclusive, inclusive]
![Page 21: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/21.jpg)
21
Hello, "Random" World!#include <iostream>#include <random>int main() { std::mt19937 mt(1729); std::uniform_int_distribution<int> dist(0, 99); for (int i = 0; i < 16; ++i) { std::cout << dist(mt) << " "; } std::cout << std::endl;}
Deterministic 32-bit seed
Engine: [0, 232)
Distribution: [0, 99]
Note: [inclusive, inclusive]Run engine,
viewed through distribution
![Page 22: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/22.jpg)
22
Hello, Random World!#include <iostream>#include <random>int main() { std::random_device rd; std::mt19937 mt(rd()); std::uniform_int_distribution<int> dist(0, 99); for (int i = 0; i < 16; ++i) { std::cout << dist(mt) << " "; } std::cout << std::endl;}
Non-deterministic 32-bit seed
![Page 23: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/23.jpg)
23
mt19937 vs. random_device• mt19937 is:• Fast (499 MB/s = 6.5 cycles/byte for me)• Extremely high quality, but not cryptographically secure• Seedable (with more than 32 bits if you want)• Reproducible (Standard-mandated algorithm)
• random_device is:• Possibly slow (1.93 MB/s = 1683 cycles/byte for me)• Strongly platform-dependent (GCC 4.8 can use IVB RDRAND)
• Possibly crypto-secure (check documentation, true for VC)• Non-seedable, non-reproducible
![Page 24: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/24.jpg)
24
uniform_int_distribution• Takes any Uniform Random Number Generator• Usually [0, 232) or [0, 264) but [1701, 1729] works• If your URNG does that, you are bad and you should feel bad
• Emits any desired range of integers [low, high]• signed/unsigned short/int/long/long long• Why not char/signed char/unsigned char? Standard Says SoTM
• Preserves perfect uniformity• Requires obsessive implementers• Uses bitwise/etc. magic, invokes URNG repeatedly (rare)• Runs fairly quickly (34% raw speed for me)
• Deterministic, but not invariant• Will vary across platforms, may vary across versions
![Page 25: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/25.jpg)
25
random_shuffle() Considered Harmful
template <typename RanIt> void random_shuffle(RanIt f, RanIt l);• May call rand()• C++ Standard Library, I trusted you!
template <typename RanIt, typename RNG>void random_shuffle(RanIt f, RanIt l, RNG&& r);• Not evil, but highly inconvenient• Knuth shuffle needs r(n) to return [0, n)
![Page 26: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/26.jpg)
26
shuffle() Considered Awesometemplate <typename RanIt, typename URNG> void shuffle(RanIt f, RanIt l, URNG&& g);• Takes URNGs directly (e.g. mt19937)• Shuffles perfectly• All permutations are equally likely
• Invokes the URNG in-place (can't copy)• Other algorithms can copy functors, like generate()• Special exception: for_each() moves functors
![Page 27: Rand() Considered Harmful Stephan T. Lavavej ("Steh-fin Lah-wah-wade") Senior Developer - Visual C++ Libraries stl@microsoft.com 1 Version 1.1 - September](https://reader035.vdocuments.site/reader035/viewer/2022062421/56649ce35503460f949afb26/html5/thumbnails/27.jpg)
27
Random <random> Notes• Running mt19937 is fast, constructing/copying isn't• Constructing/copying engines often is already undesirable
• URNG/distribution function call ops are non-const• Multiple threads cannot simultaneously call a single object
• When is it safe to skip uniform_int_distribution?• mt19937's [0, 232) or mt19937_64's [0, 264) [0, 2N)• In this case, masking is safe, simple, and efficient• In all other cases, use uniform_int_distribution