-1

To test how random the numbers that python generates are, i wrote this:

import random

l=[]
lshuf=[]
for x in range(0,101):
    lshuf.append(x)

for x in range (0,100000):
    l.append(lshuf[random.randrange(0,101)])
   
    
l2=[]
for x in range(0,101):
    l2.append(0)

for x in l:
    l2[l[x]]+=1

Basically It generates 100,000 random numbers between 0 and 100, and puts how many times the number between 0 and 100 occours in a list. When it prints out a list, this is what shows:

[0, 947, 2018, 1961, 0, 990, 1994, 0, 934, 0, 0, 976, 0, 0, 967, 1024, 2025, 2009, 2990, 949, 0, 4961, 0, 0, 1037, 951, 1998, 0, 2002, 3076, 0, 0, 0, 2086, 0, 2926, 0, 936, 996, 0, 995, 1010, 0, 0, 1004, 0, 0, 0, 0, 0, 1004, 0, 2909, 1990, 1955, 4833, 0, 1001, 0, 0, 0, 0, 2928, 0, 1976, 1018, 0, 1985, 996, 958, 3005, 0, 1918, 988, 976, 0, 3057, 0, 1010, 988, 0, 1860, 1026, 0, 945, 0, 0, 0, 1988, 999, 1871, 1034, 2976, 1010, 0, 1994, 0, 0, 983, 3026, 1031]

If it was truly random none of the items would be zero occurrences, they would mostly be between 500 and 1500. How can I generate better random numbers?

Alexander
  • 1,051
  • 1
  • 8
  • 21
  • 1
    Does this answer your question? [Can I generate authentic random number with python?](https://stackoverflow.com/questions/22891583/can-i-generate-authentic-random-number-with-python) – difurious Dec 03 '20 at 20:08
  • 3
    You need to trace and debug your code. The problem is not with the random functions, but with your accounting. – Prune Dec 03 '20 at 20:16
  • 1
    "When it prints out a list ..." your code has 3 lists and no print statements. Why not specify which list is being printed? By the way, there is no reason to use a loop to populate `l2` with `0`. Just use `l2 = [0]*100` – John Coleman Dec 03 '20 at 20:23

2 Answers2

5

Your test is incorrect.

for x in l:
    l2[l[x]]+=1

should be:

for x in l:
    l2[x]+=1

l[x] only samples from the first 100 of your 100,000 numbers.

Here's a simplified test:

import random
from collections import Counter

c = Counter()
for _ in range(100000):
    c[random.randrange(101)] += 1
result = dict(sorted(c.items()))

# >>> print(result)
# {0: 936, 1: 1011, 2: 989, 3: 1005, 4: 1036, 5: 992, 6: 1013, 7: 1008, 8: 983, 9: 987, 10: 982, 11: 991, 12: 986, 13: 973, 14: 973, 15: 988, 16: 952, 17: 1025, 18: 958, 19: 989, 20: 984, 21: 934, 22: 997, 23: 960, 24: 989, 25: 1005, 26: 1006, 27: 1019, 28: 1000, 29: 1003, 30: 1007, 31: 993, 32: 996, 33: 993, 34: 1010, 35: 1041, 36: 955, 37: 965, 38: 991, 39: 995, 40: 1036, 41: 967, 42: 1013, 43: 957, 44: 930, 45: 1037, 46: 1031, 47: 1017, 48: 1050, 49: 1005, 50: 954, 51: 968, 52: 1010, 53: 984, 54: 1012, 55: 1017, 56: 980, 57: 928, 58: 976, 59: 968, 60: 970, 61: 1011, 62: 949, 63: 1018, 64: 982, 65: 990, 66: 1011, 67: 985, 68: 1001, 69: 964, 70: 957, 71: 977, 72: 1007, 73: 1028, 74: 1049, 75: 930, 76: 949, 77: 998, 78: 981, 79: 1001, 80: 1000, 81: 976, 82: 1064, 83: 994, 84: 993, 85: 999, 86: 1007, 87: 1021, 88: 958, 89: 957, 90: 989, 91: 990, 92: 990, 93: 992, 94: 1027, 95: 973, 96: 907, 97: 973, 98: 944, 99: 979, 100: 1049}
0x5453
  • 12,753
  • 1
  • 32
  • 61
1

The random module makes pseudo-random numbers, and it's not always efficient. For a truly random module, use the secrets module.

Randomly chosen element from a sequence: secrets.choice(sequence)

Use secrets.randbelow(n) to return a random integer in the range 0, n.

Check out the documentation for more info.

jort57
  • 76
  • 1
  • 10
  • 1
    Despite the title of the question, this isn't the issue with OP's code – John Coleman Dec 03 '20 at 20:28
  • note that both `secrets` and `random` both return uniformly distributed values. it's just that the state/seed is hidden in the OS/kernel for `secrets`. `random` is **much** more efficient at generating values as well, `secrets` requires a context switch into the kernel and back which is orders of magnitude more expensive – Sam Mason Dec 04 '20 at 17:21