Compare distribution of three random integer algorithm.
python
sadrand
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sadrand.py 2.9KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #!/usr/bin/python3
  2. import random
  3. import argparse
  4. import math
  5. import sys
  6. import warnings
  7. tqdm = lambda it, **kwargs: iter(it)
  8. def std_rand(args):
  9. result = [0 for _ in range(args.resolution)];
  10. for _ in tqdm(range(args.iter), unit_scale=True, total=args.iter):
  11. result[random.randint(0, args.resolution-1)] += 1
  12. return result
  13. def std_rand_fast(args):
  14. result = [0 for _ in range(args.resolution)];
  15. nbits = math.ceil(math.log2(args.resolution))
  16. for _ in tqdm(range(args.iter), unit_scale=True, total=args.iter):
  17. while True:
  18. rnd = random.getrandbits(nbits)
  19. if rnd < args.resolution:
  20. break
  21. result[rnd] += 1
  22. return result
  23. def rnd_bytes(count, chunk_size=4096):
  24. to_read = count
  25. with open('/dev/urandom', 'br') as rfd:
  26. for _ in range((count // chunk_size) + 1):
  27. read_sz = chunk_size if to_read > chunk_size else to_read
  28. chunk = rfd.read(read_sz)
  29. to_read -= len(chunk)
  30. for res_byte in chunk:
  31. yield res_byte
  32. def generic_rand(args, rnd_fun):
  33. result = [0 for _ in range(args.resolution)];
  34. for rbyte in tqdm(rnd_bytes(args.iter), total=args.iter, unit_scale=True):
  35. result[rnd_fun(rbyte)] += 1
  36. return result
  37. mod_rand = lambda args: generic_rand(args,
  38. lambda rbyte: rbyte % args.resolution)
  39. prop_rand = lambda args: generic_rand(args,
  40. lambda rbyte:(rbyte*(args.resolution)) // 256)
  41. if __name__ == "__main__":
  42. parser = argparse.ArgumentParser();
  43. parser.add_argument('-i', '--iter', type=lambda v: int(v,0),
  44. default=0x100000);
  45. parser.add_argument('-r', '--resolution', type=lambda v: int(v,0),
  46. default=100);
  47. parser.add_argument('-c', '--chunk-size', type=int, default=4096);
  48. parser.add_argument('-R', '--relative', action="store_true",
  49. default=False);
  50. parser.add_argument('-p', '--progress', action="store_true",
  51. default=False);
  52. parser.add_argument('--std', action="store_true", default=False,
  53. help="Use random.randint instead of random.getrandbits")
  54. args = parser.parse_args();
  55. if args.progress:
  56. try:
  57. from tqdm import tqdm
  58. except (NameError, ImportError):
  59. warnings.warn("tqdm module not found, no progress bar")
  60. methods = (std_rand if args.std else std_rand_fast, mod_rand, prop_rand)
  61. results = [method(args) for method in methods]
  62. if args.relative:
  63. for i, result in enumerate(results):
  64. results[i] = [(r / args.iter) * args.resolution for r in result]
  65. for i, res in enumerate(zip(*results)):
  66. if args.relative:
  67. i = i / args.resolution
  68. sys.stdout.write(str(i) + ' ' + (' '.join([str(r) for r in res]))+'\n')