Before anything else: the Mersenne Twister algorithm. This is the default pseudo-random number generator used by Python’s random module. It produces 53-bit precision floats and has a period of 2^19937 1, which is pretty ***** impressive! However, if you need even more speed or want to use your own custom algorithm, you can subclass the Random class and override its methods.
But let’s not get ahead of ourselves. Let’s start with some basic optimizations that will make a noticeable difference in performance. First up: using the FullRandom class instead of the default random module. This is a simple trick that replaces the underlying implementation with a faster one, without sacrificing quality or accuracy.
Here’s an example script that demonstrates how to use it:
# Import the Random module from the standard library
from random import Random
# Import the math module from the standard library
import math
# Create a new class called FullRandom that inherits from the Random class
class FullRandom(Random):
# Define a method called random that overrides the random method from the Random class
def random(self):
# Create a variable called mantissa and assign it a hexadecimal value
mantissa = 0x10_0000_0000_0000 | self.getrandbits(52)
# Create a variable called exponent and assign it a value of -53
exponent = -53
# Create a variable called x and assign it a value of 0
x = 0
# Create a while loop that runs until x is not equal to 0
while not x:
# Generate a random 32-bit integer and assign it to x
x = self.getrandbits(32)
# Increase the value of exponent by the number of bits in x
exponent += x.bit_length() 32
# Use the ldexp function from the math module to combine the mantissa and exponent and return the result
return ldexp(mantissa, exponent)
# Instantiate a new FullRandom object and assign it to the variable fr
fr = FullRandom()
# Print the result of calling the random method on the fr object, which generates a random float between 0.0 and 1.0 (inclusive)
print(fr.random())
As you can see, this script defines a custom class called `FullRandom`, which is derived from the built-in `Random` class. The `random()` method has been overridden to generate a faster random float using a combination of bitwise operations and logarithmic calculations. This results in significantly better performance than the default implementation, especially for large numbers of iterations or when generating many random values at once.
If you need even greater speed, you can use the `SystemRandom` class instead. This uses the system function `os.urandom()` to generate random numbers from sources provided by your operating system. Here’s an example script that demonstrates how to use it:
# Import the necessary modules
import os # Import the os module to access system functions
from secrets import SystemRandom # Import the SystemRandom class from the secrets module
# Instantiate a new SystemRandom object and use it to generate some random bytes
sr = SystemRandom() # Create a new instance of the SystemRandom class
print(sr.getrandbits(32)) # Output: A random 32-bit integer (between 0 and 4,294,967,295)
# The above code generates a random 32-bit integer using the getrandbits() method of the SystemRandom class
# This method takes in a number of bits as an argument and returns a random integer with that many bits
# In this case, we are generating a 32-bit integer, which is the maximum size for a standard integer in Python
# If you need even greater speed, you can use the SystemRandom class instead
# This class uses the system function os.urandom() to generate random numbers from sources provided by your operating system
# Here's an example script that demonstrates how to use it:
# Import the necessary modules
import os # Import the os module to access system functions
from secrets import SystemRandom # Import the SystemRandom class from the secrets module
# Instantiate a new SystemRandom object and use it to generate some random bytes
sr = SystemRandom() # Create a new instance of the SystemRandom class
print(sr.getrandbits(32)) # Output: A random 32-bit integer (between 0 and 4,294,967,295)
# The above code generates a random 32-bit integer using the getrandbits() method of the SystemRandom class
# This method takes in a number of bits as an argument and returns a random integer with that many bits
# In this case, we are generating a 32-bit integer, which is the maximum size for a standard integer in Python
# The SystemRandom class is faster than the standard random module because it uses the os.urandom() function
# This function uses sources provided by the operating system, making it more secure and efficient for generating random numbers
As you can see, this script defines a custom class called `SystemRandom`, which is derived from the built-in `secrets.SystemRandom` class. The `getrandbits()` method has been used to generate a random 32-bit integer using the system function `os.urandom()`. This results in significantly better performance than the default implementation, especially for large numbers of iterations or when generating many random values at once.
Some simple optimizations that will make your Python code run faster and more efficiently when generating pseudo-random numbers. Give them a try and let us know how they work for you! And if you’ve got any other tips, tricks, or hacks to share, feel free to leave a comment below.