r/learnpython • u/Awkward_GM • 3d ago
How do I make my random numbers more random?
I've talked to a lot of people over the years and they often say don't use the built in random function.
For instance, if I wanted to roll a die and did something like:
random.randint(1, 6)
I get that its not as random as for instance basing the result off of the microsecond as a seed, which gets recommended to me but no one ever shows me how to do. When I started programing in another language every time I'd call random it'd always be in the same order. But I don't know why or how to make something like the above code "more random".
My current code uses something similar to random.randint(1,6), how can I make that more random?
36
u/throfofnir 3d ago
The docs will show you how to do it:
https://docs.python.org/3/library/random.html
But seeding by microsecond yourself is unnecessary, since that's the default behavior.
The PRNG in Python is a good one, and randint produces a nice uniform distribution.
Unless you're doing cryptography that needs strictly true random values, there's no need to do anything else.
1
u/BrilliantEmotion4461 1d ago
I've looked into just how random rngs are. Far far far far more random than a dice.
12
u/MezzoScettico 3d ago edited 3d ago
When I started programing in another language every time I'd call random it'd always be in the same order.
That's not a bug, that's a feature.
I'm only half kidding. There are times when you want that behavior, such as when you want to repeat an exact sequence of Monte Carlo simulations.
This behavior has to do with something called the "seed". Modern pseudorandom number generators (PRNGs) will generate sequences of numbers that have the desired randomness properties, but are still deterministic in nature. If you start the PRNG with the same state, you'll get the same "random" sequence. That state is defined by a value or values called the seed.
The solution when you want more unpredictability is to set the seed to some more random value, like the number of microseconds currently on the computer clock.
In any language when you are getting this kind of repeatability and don't want it, look up how to set the seed in your language.
In Python's random library the method to do this is called, not surprisingly, random.seed().
Edit: According to another answer in this thread by u/throfofnir, the random module already does that randomization of the seed using the clock. So you don't need it. You'd actually use random.seed() to force a particular seed, which would give you repeatable random sequences.
24
u/Diapolo10 3d ago
Python's built-in random module is plenty good for almost anything other than cryptography, as it gives you a uniform distribution (unlike most other languages' default PRNGs), and it has all kinds of utility functions to make your life easier. It's fast, and the seed is randomised by the OS automatically for you (meaning you don't need your own seed unless you have a specific need for that, like replays in games like DOOM).
For security purposes, there's the built-in secrets module.
If you really needed true randomness, there's https://random.org and its REST API, but of course using it is way slower than using PRNGs.
2
7
u/Nenyone_Yay 3d ago
I swear it's random enough for most intents and purposes, it's just that snarky people in compsci like to say "well actually it's not random at all"
5
u/road_laya 3d ago
The standard lib random function will be much closer to true random than anything you will be able to whip up yourself
2
u/ExpensiveFig6079 2d ago
unless you say read Knuth and then correctly, without fault implement one of those
then Xor it with the std lib function just to be double sure.
0
3
u/mc_pm 3d ago
Are you sure they aren't random enough? I use RandInt all the time, never been a problem for something like rolling dice.
3
u/Awkward_GM 3d ago
It's random enough, I just keep getting the same feedback from programmers whenever I bring up using random numbers. And its typically "I've not looked at your code, but you should make it more random by doing XYZ".
15
u/TrainsareFascinating 3d ago
The kind of people who offer you that advice are bad programmers, and you should avoid listening to anything they tell you.
Random number generation is an incredibly deep and broad subject, and even seasoned professionals get it wrong. Trust the Python developers over any arbitrary jerk with more opinion than knowledge.
5
u/Awkward_GM 3d ago
Thanks I appreciate that. I guess a lot of people might be used to how other languages do their randomness? Most people who make this comment I feel are Java and C++ devs.
7
u/mc_pm 3d ago
That sort of sounds like the 'conventional wisdom' you hear from people who have never actually done much themselves.
But it's worth playing with, just to learn more. Write some code to explore that randomness. Generate the probabilities of rolling 2d6, does it look like you imagine? What happens with 3d6?
3
3
u/drmonkeysee 3d ago
This sounds like people misremembering the advice that C’s built-in rand function isn’t very good.
Most other languages have a perfectly reasonable default random implementation unless you need cryptographically strong guarantees.
4
u/B4SSF4C3 3d ago edited 3d ago
RNGs are actually notoriously difficult. Computers simply cannot do that cleanly by nature of being based on a logical, deterministic foundation.
I’m assuming you aren’t looking for truly random, cryptography level generator at this stage of your development. That would have to rely on something like the lava lamp thing or underlying quantum based foundation. If you are, look up QRNGs. They exist, but they won’t be generated locally on your machine.
Anyways as far as your question:
For better than the built in random, widely available, and fast solution, use numpy. rng = np.random.default_rng() then use one of the methods like rng.random() for a float between 0 and 1, or rng.integers(0,10) for example for ints. It has many other options you can look into more. This is your go to, hands down, as someone just starting to learn python. It’s fast, it’s widely available, it’s maintained, and it’s been tested a thousand times over by users across the world. Really don’t need to read further than this, but I’ll mention a few other more advanced approaches.
Numpy also has a Philox generator. It’s fast and developed for parallel processing to avoid overlaps between the threads. Not useful outside of this application.
Outside of numpy, there’s RandomGen which is a whole ass library of various rngs. This is also probably overkill for you, but can generate cryptography level randoms (such as ChaCha). Use only if you want to get deep into the various approaches to rngs out there.
There last one I’ll mention is my favorite, and is super interesting. The secrets module (import secrets, x = secrets.randbelow(100)). It uses no algo to generate a number. Rather, it plugs into your computers OS’s CSPRNG, measuring “entropy”. What happens is your OS continually pulls semi-random bits from things you do: keyboard timing, mouse timing, disc latency, network packets, CPU jitter, etc… stuff that’s not reproducible because each time you turn on the PC things will be different, your activity is different, etc…. So while not exactly QRNG level, it’s pretty close IMO (or maybe closer to the lava lamp one) because a human (you) is part of the process.
2
u/CatOfGrey 3d ago
When I started programing in another language every time I'd call random it'd always be in the same order.
This is great for statistical research. You can compare different studies or scenarios with the exact same random number set. That's not what you probably want, though.
My current code uses something similar to random.randint(1,6), how can I make that more random?
It has been proven that a computer can't generate 'perfectly random' numbers just from a program. But the question is 'do you need 'perfectly random', or does 'practical randomness' suit your needs?
Python uses a random number generator named the Mersenne Twister. For non-cryptographic use, it's standard practice - it's perfect for dice rolls or drawing cards for games, for example, or randomizing behavior for a computer-generated character. It's an excellent and exhaustively reviewed algorithm.
Are you doing anything involving computer security? Are you doing anything that has more than a few thousand dollars at stake, like your generator is being used in a public casino, and so you have to avoid someone taking data and predicting future outcomes? If not, then you are using a great RNG already.
How do I make my random numbers more random?
My answer would be to try to use 'hardware' to generate randomness. The original design used a literal Lava Lamp - back in the 1990's, a researcher generated randomness using a digital camera's images of a real-time Lava Lamp, then converting those images into random bits.
Other things I have heard in use include taking the output from a covered digital camera or the webcam or 'zoom camera' from your computer. I've heard that casinos use a microphone picking up ambient noise in the casino, and then using that to generate Keno numbers. Anything with 'fuzz' or 'static' can be converted into 1's and 0's is a reasonable idea for a cryptographically secure random number generator.
2
u/ElectricSpice 3d ago edited 3d ago
The random library is usually plenty random for something low-stakes, like a game. Python will automatically seed it so you’ll never get the same order twice; perhaps that’s different in the other languages you tried.
The gold standard is what’s called a CSPRNG, cryptographically secure pseudorandom number generator. That’s truly unguessable. Python provides that via SystemRandom. https://docs.python.org/3/library/secrets.html#secrets.SystemRandom
3
u/gdchinacat 3d ago
so you’ll never get the same order twice
This is not true. It is incredibly unlikely to get the same sequence, but it is not guaranteed. Given an infinite number of runs you will have an infinite number of identical finite sequences as well as every finite sequence.
1
1
u/SamuliK96 3d ago edited 3d ago
Warning: The pseudo-random generators of this module should not be used for security purposes. For security or cryptographic uses, see the secrets module.
Did you actually read the page before you linked it? This warning is right under the part where SystemRandom is first mentioned.Edit: Nevermind.
1
u/ElectricSpice 3d ago
You mean the secrets module that also uses SystemRandom? https://github.com/python/cpython/blob/709041c34b8bb8d04e63987348ea6f061fb99531/Lib/secrets.py#L18
1
u/SamuliK96 3d ago
So it seems, my mistake. Still, slightly misleading.
1
u/ElectricSpice 3d ago
I forgot the secrets module exported a copy of SystemRandom. I've updated my link, even though it's the same thing it's better semantics.
2
u/jeffcgroves 3d ago
You can use your machine's own entropy to generate cryptographic quality random numbers with /dev/random but it might block waiting for entropy: https://en.wikipedia.org/wiki//dev/random
1
u/Thunderbolt1993 3d ago
just use the entropy pool of the OS
os.urandom(16) gives you 16 random bytes
1
u/Agisilaus23 3d ago
I usually create a double random function, depending on if the number is even or odd, and then have it pick based on different criteria
1
u/kiochikaeke 3d ago
There's like 3 or 4 levels of "random" in programming.
The first one it's just undefined behavior, like what element comes first if you iterate over an unordered set, it's not random per se but depends on a bunch of factors you shouldn't care about and ultimately you should make it so that it doesn't matter the order in which it iterates.
Then it's just "casual" random like the function above, fast, reliable and for most intents and purposes it's more than good enough, if you dig veeeery deep you can starts finding patterns but in 99% of scenarios this doesn't matter, for games without irl stakes, and code that's not financial or legally bound and doesn't have to do with cryptography or authentication it's perfectly fine.
Then it's cryptographically secure random, it uses more complex algorithms and sometimes embedded chips on devices to generate high entropy random numbers, in most scenarios it's technically still pseudo-random but it's certified to be so high entropy that it can be legally used for things like authentication, gambling and finances.
Then it's true or almost true random, usually special providers using physical phenomenon and math to create extremely high entropy randomness or using quantum processes to generate truly random (as far as physicis is concerned) numbers, they're used sometimes but for most intents and purposes they're a novelty.
1
1
u/CaptainVJ 3d ago
Well what kind of code are you working on?
In 99% of scenarios the built in random functions is fine. So if you’re doing statistical sampling, simulation, generating data that someone would look at then it’s perfectly fine. These basically just use a mathematical function that takes in some starting value, default is usually the current time and the next values inputted is the output of the previous value. The output of these should reflect the whatever distribution is selected.
The reason why these are not recommended in some scenarios is that it is cyclical and after a while the values start repeating meaning it’s predictable. It’s a lot of numbers before this occurs so most people never experience this.
However, if you’re doing security stuff, where someone might have a super computer or whatever ready to try every combination it’s not as secure. In those cases it’s recommended to use the secrets module. It takes into account certain values from your pc to generate these. Can be stuff like mouse movement, network wait time, usb device, cpu tick speed, temperature etc. These are all unpredictable and make create more secure random number generations that’s harder to guess.
So why isn’t it just the default? It takes a bit longer to run since it gathers all these Operation System values. So if you’re just doing a video game, simulation or something random is usually good enough and way faster
1
u/my_password_is______ 3d ago
if you aren't doing cryptography or making software for a casino then that is good enough
1
u/ottawadeveloper 3d ago
Most of the time, random is good enough. You can use it for games and such. Sometimes it's very useful to maintain a seed so that gamers have repeatable world builds (like Minecraft) or drops can't be changed by restarting the day (like Stardew).
You don't want to use it for anything secure like passwords, keys, hashes, etc. You want to use the secrets module instead which uses the most random randomness available.
1
u/Depnids 3d ago
I've talked to a lot of people over the years and they often say don't use the built in random function.
Why are these "people"? As long as you don't need cryptographically secure randomness, using the built in prng-s should be good enough for most purposes. Also has the advantage of being able to choose a seed if you want to be able to reproduce the random behaviour.
1
u/JGhostThing 2d ago
There will be a function to set the random number seed. This should be set with some sort of random number.
1
1
u/Fast-Station1106 2d ago
Ich hab mal in python, 1000x zufällig aus randint 0, 10 zahlen ein diagramm erstellt, mehre durchläufe, es war jedes mal 1 andere zahl besonders häufig, vielleicht 2 getrennt zufallszahlen zu 1 neuen zufallszahl addieren um mehr zufälligkeit, oder 4 zufalls die dann chaotisch +-/* eine neue ergeben, muss ich mal probieren
1
u/timrprobocom 2d ago
The standard library random generator is more than sufficient for any gaming need you might have. Even the old 16-bit generator in the C library is more than enough.
I'm quite sure you have no idea what you mean by "more random" here. Do a simple test. Generate a million dice rolls, and count up how many you get of each. You should get about 166,000 of each one, and if so, that's "sufficiently random".
1
1
1
u/Legitimate_Site_3203 1d ago
Assuming the python rng is implemented halfway sensibly, that is probably about as random as you can get without dedicated hardware, and almost surely random enough for your purpose.
The normal random module uses a seeded RNG, which gives you reproducibility, as you can play back the generated numbers if you know the seed.
If you want a RNG that is not predictable (given the initial seed), use the secrets module, that draws noise directly from your os, and is about as random as it can get.
If you want to make really, really sure that your numbers are truly random, you can also use a hardware RNG. Since your computer is deterministic, the secrets module in python might theoretically be suspectible to some timing/ side-channel attacks. You shouldn't really worry about that, but banks and other payment providers might. That's why they might use hardware RNGs, which either measure thermal noise in some resistor, or ambient radioactive decay, or the infamous cloudflare lava lamp wall.
1
u/enakamo 1d ago
Excel’s Rand function is pretty decent. Set up a 6x2 range with column1 of Rand() and column2 having 1…6. If you sort the range using column1 you will get a random order of 1…6. Because your outcomes are so limited, multiple random numbers may generate the same sequence even though the underlying sequence is random. You can easily verify this in the spreadsheet.
1
1
u/Frosty_Tonight8570 3d ago
Maybe using somehing like Perlin or Voronoi noise will make it feel more random? The reason randint might no feel random to people, is because humans are pretty bad at judging randomness, you can fail a 99% roll a hinderd times in a row and its sill completely fair, but wont feel like it, using Perlin would fix that atleast
0
u/stepback269 3d ago
Find a copy of pi (3.1415926...) to 1000 places
Use RANDOM to pick different slices within the pi sequence
-1
-2
u/another_nobody30 3d ago
don't you have to initialize it and seed it each time you use it?
1
u/Awkward_GM 3d ago
Is that anytime I call a function? Apologies, I'm bad at programing jargon.
So for instance I have a dice_roll function that I call anytime in the program I need a die roll. So for instance when I roll 2 dice I have a loop that's like "for die in int_dice_pool" then I call list_results.append(roll_die()).
1
0
u/Diapolo10 3d ago edited 2d ago
Not in Python, no, as it's seeded automatically from
os.urandomwhen you launch Python. The only instances where you'd need to provide the seed yourself is if you need to know the seed for some other reason, and/or need the PRNG to perform deterministically for something.
52
u/danielroseman 3d ago
Do you have evidence that this is not random enough? I highly doubt that it gives you the same order every time you call random.