8 ms·
This change makes me SO HAPPY: The math/rand package now automatically seeds the global random number generator (used by top-level functions like Floa
by pianoben 4y ago
This change makes me SO HAPPY:
The math/rand package now automatically seeds the global random number
generator (used by top-level functions like Float64 and Int) with a random
value, and the top-level Seed function has been deprecated. Programs that
need a reproducible sequence of random numbers should prefer to allocate
their own random source, using rand.New(rand.NewSource(seed)).
We've had some truly nasty bugs from people who weren't familiar with the prior behavior of having a default seed of zero for the global random-number generator. This is going to save many people so much heartache.
- gouggoug 4y agoWould you be able to expand on why using a seed of 0 is an issue?
- deleted 4y ago[deleted]
- pianoben 4y agoIf you randomly generate numbers using `math/rand`, then every invocation of your program is going to see the same sequence of "random" numbers. If you happen to persist those random numbers and expect a uniform distribution, you're going to be sadly surprised in the future. It's the kind of "bug" that doesn't manifest until your data is thoroughly boned.
- gouggoug 4y agoSo, if I use `math/rand` the RNG will always output the same sequence of random numbers? How do I make sure I'm passing a random seed to my RNG? (I must be missing something here)
- chimeracoder 4y ago> So, if I use `math/rand` the RNG will always output the same sequence of random numbers? math/rand provides global functions using a global RNG, as well as the ability to instantiate your own RNG and call functions (methods) on that RNG. Previously, the global functions all used a seed of 1, which made them generate identical sequences. Now, they use random seed, which makes them less-easily predictable (though still predictable). There is no change to the self-instantiated RNGs. > How do I make sure I'm passing a random seed to my RNG? With the change, using the global functions in Go 1.20+ is the same as instantiating your own RNG with a random seed.
- Brentward 4y agoThe example in previous versions of the Go math/rand package suggested using time.Now().UnixNano() to seed the RNG source since that's essentially a random int64.
- morepork 4y agoIt's a reasonable choice, and will be unique for most program runs, but it's not exactly random
- ihatepython 4y agoPhilosophically, there is no such thing as a random number
- dharmab 4y agoThere are ways to get truly random numbers into a computer. Certain phenomena are theorized to be fundamentally random, and can be used as inputs to hardware. https://en.m.wikipedia.org/wiki/Hardware_random_number_generator https://en.m.wikipedia.org/wiki/Hardware_random_number_gener...
- majewsky 4y agoThe sound of conviction in your first sentence does not match the "theorized to be" in the second sentence. I recommend that you don't bring a "for all intents and purposes" to a "philosophically" fight. ;)
- mseepgood 4y agoHowever, the universe is based on randomness at its quantum core.
- morepork 4y agoOr perhaps the universe is a simulation whose prng was seeded with 1 just like golang does Maybe we're in the first batch of simulations, and the tester came along and asks why they're all identical. The cosmic coder then realises that they forgot to call the function to seed the prng.
- kiernanmcgowan 4y agoHaving the seed value set to the same value at run time will cause the pseudorandom number generator to produce the same sequence of values. In essence just creating a new random number generator in go w/o setting the seed will not actually generate random values.
- chimeracoder 4y ago> In essence just creating a new random number generator in go w/o setting the seed will not actually generate random values. This change only affects the global RNG. Creating a new RNG has always required setting a seed
- akira2501 4y agoWhich is also significant because the global RNG is safe for concurrent use. Instantiated RNGs are not.
- chimeracoder 4y ago> Which is also significant because the global RNG is safe for concurrent use. Instantiated RNGs are not. Amusingly, I submitted a patch for this some years ago, and it was rejected on the grounds that callers might depend on the specific sequence of numbers outputted by the global RNG using the default seed, which could break the compatibility promise. Now that that's been deemed a non-issue, I might resubmit.
- e12e 4y agoTo be clear, if setting a global seed was required it would not be so bad - but silently seeding with 1 is an edge that's pretty easy to trip on.
- wvh 4y agoThe generator returns the same sequence every time. For instance Kubernetes CSI drivers have a supposedly unique csiProvisionerIdentity but it uses math/rand without seeding so they're all using the integer number 8081.
- apatheticonion 4y agoIt appears like it's an API design that intersects the world of high level application development and computer science. Given randomness requires a seed and UNIX's ISO standard defines the default seed as 0, it's rational from a comp sci perspective to expect to supply a seed to produce a random number. However, due to how ergonomic and safe high level languages are today, you don't need to be a computer scientist to make a highly available, beautiful and robust application. As such, the inhabitants of the application development world are considerably less concerned with such details and want, when they call a thing, it gives an intuitive result. It's important that tool makers consider their users when creating APIs. Supplying a seed to a function called "getRandomNumber" might be obvious to a C programmer, but not obvious to a JavaScript programmer looking to use Go to improve the performance of their back end service.
- chimeracoder 4y ago> We've had some truly nasty bugs from people who weren't familiar with the prior behavior of having a default seed of zero for the global random-number generator. This is going to save many people so much heartache. Agreed, but worth nothing that this does not make it cryptographically secure. The output can still be predicted. For cryptographic security, you need crypto/rand: https://pkg.go.dev/crypto/rand https://pkg.go.dev/crypto/rand In general, my advice is to use the cryptographically secure RNG unless you specifically know you need reproducibility (e.g. scientific simulation, or map generation in video games). With non-secure RNGs, it's very easy to accidentally expose yourself to problems without realizing it. (Also, FYI, the default seed was 1, not 0).
- tptacek 4y agoThe whole point of math/rand is that it's not cryptographically secure.
- chimeracoder 4y ago> The whole point of math/rand is that it's not cryptographically secure. Sure, and that's even been in the documentation since before Go 1.0, yet people still make mistakes with it in practice. I've found it worth making the point explicit. Particularly in a case like this, where a casual reader might not notice the distinction between "non-reproducible" and "secure".
- tptacek 4y agoOK, but a good sign that you're not using a cryptographic RNG is that you're somehow "seeding" it.
- chimeracoder 4y ago> OK, but a good sign that you're not using a cryptographic RNG is that you're somehow "seeding" it. The change here is specific to the global RNG, which users often used without explicitly seeding - e.g. calling rand.Int() without first calling the now-deprecated rand.Seed(int64). The distinction is obvious to people who have domain expertise here, but I've found many people make mistakes with it in practice, because it's easy to do.
- SpaghettiX 4y agoHow does the seed value get created randomly? I presume it doesn't use the same global random number generator, since that would still make it deterministic?
- deleted 4y ago[deleted]
- Scaevolus 4y agoIt's seeded using the CPU tick counter (RDTSC on x86-64), which is sufficiently random (billions of increments per second of uptime!) for this. https://cs.opensource.google/go/go/+/refs/tags/go1.20:src/math/rand/rand.go;l=415 https://cs.opensource.google/go/go/+/refs/tags/go1.20:src/ma... https://cs.opensource.google/go/go/+/release-branch.go1.20:src/runtime/stubs.go;l=132 https://cs.opensource.google/go/go/+/release-branch.go1.20:s... https://cs.opensource.google/go/go/+/release-branch.go1.20:src/runtime/proc.go;l=827 https://cs.opensource.google/go/go/+/release-branch.go1.20:s... https://cs.opensource.google/go/go/+/master:src/runtime/asm_amd64.s;l=1078 https://cs.opensource.google/go/go/+/master:src/runtime/asm_...
- cpeterso 4y agoI’m surprised they don’t just seed using /dev/urandom (or the platform specific analogue).
- remus 4y agoI remember when I started programming this was one of the first quirks that really surprised me, I can just hear myself exclaiming "This is meant to be random! Why do I keep getting the same result?!" I feel strangely vindicated seeing this change.
- pkulak 4y agoOnly if you started programming in Go. I've never in my life heard of another project that by default seeds with 0. That's insane. EDIT: Okay, C and a bunch of other languages I don't use. Keep the roasts coming, guys. :D
- rileymat2 4y agoI thought C did that?
- philosopher1234 4y agoWhy is that insane?
- jeffparsons 4y agoBecause almost everyone who asks for a random number expects a random number. Reusing a predictable seed _by default_ violates that totally reasonable expectation. (BTW, I'm deliberately avoiding making any distinction between so-called "true random" and PRNG above, because the difference isn't actually meaningful here!)
- deleted 4y ago[deleted]
- sidlls 4y agoI always thought it was perfectly intuitive that "random" wasn't really random on a computer.
- SAI_Peregrinus 4y ago
- benatkin 4y agoIIRC this is how QBasic worked back in the early 90s. I wish I had found this little throwback (whether accidental or not) before it got fixed - though I definitely agree with the change. F
- donatj 4y agoHear me out, I think in its deprecated-but-not-removed state it is actually more dangerous. Projects who have been seeding the random generator like they should suddenly think “oh I don’t need to do that anymore” and get rid of their manual seeding. Then a compromised or rogue library decides to seed the global generator themselves to a hard coded value in an `init()`, thus meaning merely importing the library re-statics the seed. It would look pretty innocuous and non-obvious in code AND be potentially pretty difficult to notice it happening in a lot of use cases. For bonus points/making it slightly harder to detect points they could even have a random set of seeds they use. The right answer, probably just generally anyway, is to never use the global generator, and always create your own instance. Global state is a danger once again
- spoiler 4y agoDo we know if the Seed function is now noop or does it set the seed value like previous? I don't think people would use the "global" random functions for deterministic randomness. At least I hope they didn't...
- tapirl 4y agoIt does set the seed value like previous. The docs says calling Seed(1) forces the old behavior. https://pkg.go.dev/math/rand#Seed https://pkg.go.dev/math/rand#Seed
- pgwhalen 4y agoI agree that would be a rough situation, but why would a library ever do that in the first place?
- Arbortheus 4y agoE.g. a supply chain attack.
- 65a 4y agoI think that's an interesting case, but any program where the random numbers have security implications should already be using crypto/rand, and not math/rand anyway.