Even though you are implementing your own random number generator, I would stick to the interface defined in the standard library module random. You could have a random, a uniform, a randint (or randrange if it is inclusive on the end) and a choices method.
Your class should probably also allow setting the seed on creation.
Python has an official style-guide, PEP8, which recommends not using trailing ; and using lower_case both for variables as well as functions/methods.
Even in Python 2 (which you should no longer use), if either the numerator or the divisor is a float, the result is also a float with the division operator /, so you only need to cast one of them. In Python 3 / is always float division and // is always integer division, so no need for the casts to float.
You should always add a dosctring to your code explaining how to use it.
For range, the start is implicitly 0. Also _ is conventionally used for unused loop variables.
Wrap the code that uses your class in a if __name__ == "__main__": guard to allow importing from this script without it running.
class Random: """A pseudo-random number generator using a LCG.""" m = 4294967296 # modulus a = 1664525 # multiplier c = 1013904223 # increment def __init__(self, seed=1): """Initialize the pseudo-random number generator with a seed (default: 1).""" self.state = seed def randint(self, a=None, b=None): """Return either a random integer between `0` and `self.m` or between `a` and `b` (exclusive?).""" if a is None and b is None: self.state = (self.a * self.state + self.c) % self.m return self.state elif a is not None: if b is not None: return int(self.uniform(a, b)) else: return int(self.uniform(0, a)) else: raise ValueError("Need to also set `a` if you set `b`.") def random(self): """Return a random float between 0 and 1 (exclusive?).""" return float(self.randint()) / self.m def uniform(self, a, b): """Return a random float between `a` and `b` (exclusive?).""" return (b - a) * self.random() + a def choices(self, population, k=1): """Return a k sized list of population elements chosen with replacement.""" n = len(population) return [population[self.randint(n - 1)] for _ in range(k)]
The usage of this is similar to your code, just with renamed methods.
You can also greatly shorten your examples using list comprehensions and a utility function mean:
random = Random() def mean(x): return float(sum(x)) / len(x) if __name__ == "__main__": N = 999999 population = [random.random() for _ in range(N)] print("Population mean = ", mean(population)) rnd_num_count = 30 sample_size = 12 sample_means = [mean(random.choices(population, k=sample_size)) for _ in range(rnd_num_count)] print("Mean of sample mean = ", mean(sample_means))
This script has the advantage that you can easily test it with the standard library random module by replacing the line random = Random() with import random. This way you can see if your class produces random numbers somewhat correctly.
If implementing so many different random functions gets tedious, you can also subclass random.Random:
Class Random can also be subclassed if you want to use a different basic generator of your own devising: in that case, override the following methods: random(), seed(), getstate(), and setstate(). Optionally, implement a getrandbits() method so that randrange() can cover arbitrarily large ranges.
This of course means that you are using the standard library and not your own implementations as much. In that case you probably also want to use statistics.mean.
randommodule in the standard library, right? If so, consider adding the reinventing-the-wheel tag. \$\endgroup\$forloop. \$\endgroup\$sample_meanswould contain only the last sample mean andsumswill be reset every loop iteration without being used, sosample_meanwill only use thesumsfrom the last iteration. \$\endgroup\$