mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Update random from v3.14.3
This commit is contained in:
committed by
Jeong, YunWon
parent
cc4a7bbbe5
commit
c4de2a7239
149
Lib/random.py
vendored
149
Lib/random.py
vendored
@@ -50,39 +50,18 @@ General notes on the underlying Mersenne Twister core generator:
|
||||
# Adrian Baddeley. Adapted by Raymond Hettinger for use with
|
||||
# the Mersenne Twister and os.urandom() core generators.
|
||||
|
||||
from warnings import warn as _warn
|
||||
from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil
|
||||
from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin
|
||||
from math import tau as TWOPI, floor as _floor, isfinite as _isfinite
|
||||
from math import lgamma as _lgamma, fabs as _fabs, log2 as _log2
|
||||
try:
|
||||
from os import urandom as _urandom
|
||||
except ImportError:
|
||||
# XXX RUSTPYTHON
|
||||
# On wasm, _random.Random.random() does give a proper random value, but
|
||||
# we don't have the os module
|
||||
def _urandom(*args, **kwargs):
|
||||
raise NotImplementedError("urandom")
|
||||
_os = None
|
||||
from _collections_abc import Set as _Set, Sequence as _Sequence
|
||||
from os import urandom as _urandom
|
||||
from _collections_abc import Sequence as _Sequence
|
||||
from operator import index as _index
|
||||
from itertools import accumulate as _accumulate, repeat as _repeat
|
||||
from bisect import bisect as _bisect
|
||||
try:
|
||||
import os as _os
|
||||
except ImportError:
|
||||
# XXX RUSTPYTHON
|
||||
# On wasm, we don't have the os module
|
||||
_os = None
|
||||
import os as _os
|
||||
import _random
|
||||
|
||||
try:
|
||||
# hashlib is pretty heavy to load, try lean internal module first
|
||||
from _sha2 import sha512 as _sha512
|
||||
except ImportError:
|
||||
# fallback to official implementation
|
||||
from hashlib import sha512 as _sha512
|
||||
|
||||
__all__ = [
|
||||
"Random",
|
||||
"SystemRandom",
|
||||
@@ -118,6 +97,7 @@ SG_MAGICCONST = 1.0 + _log(4.5)
|
||||
BPF = 53 # Number of bits in a float
|
||||
RECIP_BPF = 2 ** -BPF
|
||||
_ONE = 1
|
||||
_sha512 = None
|
||||
|
||||
|
||||
class Random(_random.Random):
|
||||
@@ -172,13 +152,23 @@ class Random(_random.Random):
|
||||
a = -2 if x == -1 else x
|
||||
|
||||
elif version == 2 and isinstance(a, (str, bytes, bytearray)):
|
||||
global _sha512
|
||||
if _sha512 is None:
|
||||
try:
|
||||
# hashlib is pretty heavy to load, try lean internal
|
||||
# module first
|
||||
from _sha2 import sha512 as _sha512
|
||||
except ImportError:
|
||||
# fallback to official implementation
|
||||
from hashlib import sha512 as _sha512
|
||||
|
||||
if isinstance(a, str):
|
||||
a = a.encode()
|
||||
a = int.from_bytes(a + _sha512(a).digest())
|
||||
|
||||
elif not isinstance(a, (type(None), int, float, str, bytes, bytearray)):
|
||||
raise TypeError('The only supported seed types are: None,\n'
|
||||
'int, float, str, bytes, and bytearray.')
|
||||
raise TypeError('The only supported seed types are:\n'
|
||||
'None, int, float, str, bytes, and bytearray.')
|
||||
|
||||
super().seed(a)
|
||||
self.gauss_next = None
|
||||
@@ -255,11 +245,10 @@ class Random(_random.Random):
|
||||
def _randbelow_with_getrandbits(self, n):
|
||||
"Return a random int in the range [0,n). Defined for n > 0."
|
||||
|
||||
getrandbits = self.getrandbits
|
||||
k = n.bit_length()
|
||||
r = getrandbits(k) # 0 <= r < 2**k
|
||||
r = self.getrandbits(k) # 0 <= r < 2**k
|
||||
while r >= n:
|
||||
r = getrandbits(k)
|
||||
r = self.getrandbits(k)
|
||||
return r
|
||||
|
||||
def _randbelow_without_getrandbits(self, n, maxsize=1<<BPF):
|
||||
@@ -270,9 +259,10 @@ class Random(_random.Random):
|
||||
|
||||
random = self.random
|
||||
if n >= maxsize:
|
||||
_warn("Underlying random() generator does not supply \n"
|
||||
"enough bits to choose from a population range this large.\n"
|
||||
"To remove the range limitation, add a getrandbits() method.")
|
||||
from warnings import warn
|
||||
warn("Underlying random() generator does not supply \n"
|
||||
"enough bits to choose from a population range this large.\n"
|
||||
"To remove the range limitation, add a getrandbits() method.")
|
||||
return _floor(random() * n)
|
||||
rem = maxsize % n
|
||||
limit = (maxsize - rem) / maxsize # int(limit * maxsize) % n == 0
|
||||
@@ -345,8 +335,11 @@ class Random(_random.Random):
|
||||
def randint(self, a, b):
|
||||
"""Return random integer in range [a, b], including both end points.
|
||||
"""
|
||||
|
||||
return self.randrange(a, b+1)
|
||||
a = _index(a)
|
||||
b = _index(b)
|
||||
if b < a:
|
||||
raise ValueError(f"empty range in randint({a}, {b})")
|
||||
return a + self._randbelow(b - a + 1)
|
||||
|
||||
|
||||
## -------------------- sequence methods -------------------
|
||||
@@ -430,11 +423,11 @@ class Random(_random.Random):
|
||||
cum_counts = list(_accumulate(counts))
|
||||
if len(cum_counts) != n:
|
||||
raise ValueError('The number of counts does not match the population')
|
||||
total = cum_counts.pop()
|
||||
total = cum_counts.pop() if cum_counts else 0
|
||||
if not isinstance(total, int):
|
||||
raise TypeError('Counts must be integers')
|
||||
if total <= 0:
|
||||
raise ValueError('Total of counts must be greater than zero')
|
||||
if total < 0:
|
||||
raise ValueError('Counts must be non-negative')
|
||||
selections = self.sample(range(total), k=k)
|
||||
bisect = _bisect
|
||||
return [population[bisect(cum_counts, s)] for s in selections]
|
||||
@@ -801,12 +794,18 @@ class Random(_random.Random):
|
||||
|
||||
sum(random() < p for i in range(n))
|
||||
|
||||
Returns an integer in the range: 0 <= X <= n
|
||||
Returns an integer in the range:
|
||||
|
||||
0 <= X <= n
|
||||
|
||||
The integer is chosen with the probability:
|
||||
|
||||
P(X == k) = math.comb(n, k) * p ** k * (1 - p) ** (n - k)
|
||||
|
||||
The mean (expected value) and variance of the random variable are:
|
||||
|
||||
E[X] = n * p
|
||||
Var[x] = n * p * (1 - p)
|
||||
Var[X] = n * p * (1 - p)
|
||||
|
||||
"""
|
||||
# Error check inputs and handle edge cases
|
||||
@@ -1005,5 +1004,75 @@ if hasattr(_os, "fork"):
|
||||
_os.register_at_fork(after_in_child=_inst.seed)
|
||||
|
||||
|
||||
# ------------------------------------------------------
|
||||
# -------------- command-line interface ----------------
|
||||
|
||||
|
||||
def _parse_args(arg_list: list[str] | None):
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.RawTextHelpFormatter, color=True)
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument(
|
||||
"-c", "--choice", nargs="+",
|
||||
help="print a random choice")
|
||||
group.add_argument(
|
||||
"-i", "--integer", type=int, metavar="N",
|
||||
help="print a random integer between 1 and N inclusive")
|
||||
group.add_argument(
|
||||
"-f", "--float", type=float, metavar="N",
|
||||
help="print a random floating-point number between 0 and N inclusive")
|
||||
group.add_argument(
|
||||
"--test", type=int, const=10_000, nargs="?",
|
||||
help=argparse.SUPPRESS)
|
||||
parser.add_argument("input", nargs="*",
|
||||
help="""\
|
||||
if no options given, output depends on the input
|
||||
string or multiple: same as --choice
|
||||
integer: same as --integer
|
||||
float: same as --float""")
|
||||
args = parser.parse_args(arg_list)
|
||||
return args, parser.format_help()
|
||||
|
||||
|
||||
def main(arg_list: list[str] | None = None) -> int | str:
|
||||
args, help_text = _parse_args(arg_list)
|
||||
|
||||
# Explicit arguments
|
||||
if args.choice:
|
||||
return choice(args.choice)
|
||||
|
||||
if args.integer is not None:
|
||||
return randint(1, args.integer)
|
||||
|
||||
if args.float is not None:
|
||||
return uniform(0, args.float)
|
||||
|
||||
if args.test:
|
||||
_test(args.test)
|
||||
return ""
|
||||
|
||||
# No explicit argument, select based on input
|
||||
if len(args.input) == 1:
|
||||
val = args.input[0]
|
||||
try:
|
||||
# Is it an integer?
|
||||
val = int(val)
|
||||
return randint(1, val)
|
||||
except ValueError:
|
||||
try:
|
||||
# Is it a float?
|
||||
val = float(val)
|
||||
return uniform(0, val)
|
||||
except ValueError:
|
||||
# Split in case of space-separated string: "a b c"
|
||||
return choice(val.split())
|
||||
|
||||
if len(args.input) >= 2:
|
||||
return choice(args.input)
|
||||
|
||||
return help_text
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
_test()
|
||||
print(main())
|
||||
|
||||
398
Lib/test/test_random.py
vendored
398
Lib/test/test_random.py
vendored
@@ -4,6 +4,7 @@ import random
|
||||
import os
|
||||
import time
|
||||
import pickle
|
||||
import shlex
|
||||
import warnings
|
||||
import test.support
|
||||
|
||||
@@ -13,6 +14,15 @@ from test import support
|
||||
from fractions import Fraction
|
||||
from collections import abc, Counter
|
||||
|
||||
|
||||
class MyIndex:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __index__(self):
|
||||
return self.value
|
||||
|
||||
|
||||
class TestBasicOps:
|
||||
# Superclass with tests common to all generators.
|
||||
# Subclasses must arrange for self.gen to retrieve the Random instance
|
||||
@@ -141,6 +151,7 @@ class TestBasicOps:
|
||||
# Exception raised if size of sample exceeds that of population
|
||||
self.assertRaises(ValueError, self.gen.sample, population, N+1)
|
||||
self.assertRaises(ValueError, self.gen.sample, [], -1)
|
||||
self.assertRaises(TypeError, self.gen.sample, population, 1.0)
|
||||
|
||||
def test_sample_distribution(self):
|
||||
# For the entire allowable range of 0 <= k <= N, validate that
|
||||
@@ -224,8 +235,6 @@ class TestBasicOps:
|
||||
sample(['red', 'green', 'blue'], counts=10, k=10) # counts not iterable
|
||||
with self.assertRaises(ValueError):
|
||||
sample(['red', 'green', 'blue'], counts=[-3, -7, -8], k=2) # counts are negative
|
||||
with self.assertRaises(ValueError):
|
||||
sample(['red', 'green', 'blue'], counts=[0, 0, 0], k=2) # counts are zero
|
||||
with self.assertRaises(ValueError):
|
||||
sample(['red', 'green'], counts=[10, 10], k=21) # population too small
|
||||
with self.assertRaises(ValueError):
|
||||
@@ -233,6 +242,20 @@ class TestBasicOps:
|
||||
with self.assertRaises(ValueError):
|
||||
sample(['red', 'green', 'blue'], counts=[1, 2, 3, 4], k=2) # too many counts
|
||||
|
||||
# Cases with zero counts match equivalents without counts (see gh-130285)
|
||||
self.assertEqual(
|
||||
sample('abc', k=0, counts=[0, 0, 0]),
|
||||
sample([], k=0),
|
||||
)
|
||||
self.assertEqual(
|
||||
sample([], 0, counts=[]),
|
||||
sample([], 0),
|
||||
)
|
||||
with self.assertRaises(ValueError):
|
||||
sample([], 1, counts=[])
|
||||
with self.assertRaises(ValueError):
|
||||
sample('x', 1, counts=[0])
|
||||
|
||||
def test_choices(self):
|
||||
choices = self.gen.choices
|
||||
data = ['red', 'green', 'blue', 'yellow']
|
||||
@@ -246,6 +269,7 @@ class TestBasicOps:
|
||||
choices(data, range(4), k=5),
|
||||
choices(k=5, population=data, weights=range(4)),
|
||||
choices(k=5, population=data, cum_weights=range(4)),
|
||||
choices(data, k=MyIndex(5)),
|
||||
]:
|
||||
self.assertEqual(len(sample), 5)
|
||||
self.assertEqual(type(sample), list)
|
||||
@@ -356,118 +380,40 @@ class TestBasicOps:
|
||||
self.assertEqual(x1, x2)
|
||||
self.assertEqual(y1, y2)
|
||||
|
||||
@support.requires_IEEE_754
|
||||
def test_53_bits_per_float(self):
|
||||
span = 2 ** 53
|
||||
cum = 0
|
||||
for i in range(100):
|
||||
cum |= int(self.gen.random() * span)
|
||||
self.assertEqual(cum, span-1)
|
||||
|
||||
def test_getrandbits(self):
|
||||
getrandbits = self.gen.getrandbits
|
||||
# Verify ranges
|
||||
for k in range(1, 1000):
|
||||
self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k)
|
||||
self.assertEqual(self.gen.getrandbits(0), 0)
|
||||
self.assertTrue(0 <= getrandbits(k) < 2**k)
|
||||
self.assertEqual(getrandbits(0), 0)
|
||||
|
||||
# Verify all bits active
|
||||
getbits = self.gen.getrandbits
|
||||
for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]:
|
||||
all_bits = 2**span-1
|
||||
cum = 0
|
||||
cpl_cum = 0
|
||||
for i in range(100):
|
||||
v = getbits(span)
|
||||
v = getrandbits(span)
|
||||
cum |= v
|
||||
cpl_cum |= all_bits ^ v
|
||||
self.assertEqual(cum, all_bits)
|
||||
self.assertEqual(cpl_cum, all_bits)
|
||||
|
||||
# Verify argument checking
|
||||
self.assertRaises(TypeError, self.gen.getrandbits)
|
||||
self.assertRaises(TypeError, self.gen.getrandbits, 1, 2)
|
||||
self.assertRaises(ValueError, self.gen.getrandbits, -1)
|
||||
self.assertRaises(TypeError, self.gen.getrandbits, 10.1)
|
||||
|
||||
def test_pickling(self):
|
||||
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||
state = pickle.dumps(self.gen, proto)
|
||||
origseq = [self.gen.random() for i in range(10)]
|
||||
newgen = pickle.loads(state)
|
||||
restoredseq = [newgen.random() for i in range(10)]
|
||||
self.assertEqual(origseq, restoredseq)
|
||||
|
||||
def test_bug_1727780(self):
|
||||
# verify that version-2-pickles can be loaded
|
||||
# fine, whether they are created on 32-bit or 64-bit
|
||||
# platforms, and that version-3-pickles load fine.
|
||||
files = [("randv2_32.pck", 780),
|
||||
("randv2_64.pck", 866),
|
||||
("randv3.pck", 343)]
|
||||
for file, value in files:
|
||||
with open(support.findfile(file),"rb") as f:
|
||||
r = pickle.load(f)
|
||||
self.assertEqual(int(r.random()*1000), value)
|
||||
|
||||
def test_bug_9025(self):
|
||||
# Had problem with an uneven distribution in int(n*random())
|
||||
# Verify the fix by checking that distributions fall within expectations.
|
||||
n = 100000
|
||||
randrange = self.gen.randrange
|
||||
k = sum(randrange(6755399441055744) % 3 == 2 for i in range(n))
|
||||
self.assertTrue(0.30 < k/n < .37, (k/n))
|
||||
|
||||
def test_randbytes(self):
|
||||
# Verify ranges
|
||||
for n in range(1, 10):
|
||||
data = self.gen.randbytes(n)
|
||||
self.assertEqual(type(data), bytes)
|
||||
self.assertEqual(len(data), n)
|
||||
|
||||
self.assertEqual(self.gen.randbytes(0), b'')
|
||||
|
||||
# Verify argument checking
|
||||
self.assertRaises(TypeError, self.gen.randbytes)
|
||||
self.assertRaises(TypeError, self.gen.randbytes, 1, 2)
|
||||
self.assertRaises(ValueError, self.gen.randbytes, -1)
|
||||
self.assertRaises(TypeError, self.gen.randbytes, 1.0)
|
||||
|
||||
def test_mu_sigma_default_args(self):
|
||||
self.assertIsInstance(self.gen.normalvariate(), float)
|
||||
self.assertIsInstance(self.gen.gauss(), float)
|
||||
|
||||
|
||||
try:
|
||||
random.SystemRandom().random()
|
||||
except NotImplementedError:
|
||||
SystemRandom_available = False
|
||||
else:
|
||||
SystemRandom_available = True
|
||||
|
||||
@unittest.skipUnless(SystemRandom_available, "random.SystemRandom not available")
|
||||
class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
gen = random.SystemRandom()
|
||||
|
||||
def test_autoseed(self):
|
||||
# Doesn't need to do anything except not fail
|
||||
self.gen.seed()
|
||||
|
||||
def test_saverestore(self):
|
||||
self.assertRaises(NotImplementedError, self.gen.getstate)
|
||||
self.assertRaises(NotImplementedError, self.gen.setstate, None)
|
||||
|
||||
def test_seedargs(self):
|
||||
# Doesn't need to do anything except not fail
|
||||
self.gen.seed(100)
|
||||
|
||||
def test_gauss(self):
|
||||
self.gen.gauss_next = None
|
||||
self.gen.seed(100)
|
||||
self.assertEqual(self.gen.gauss_next, None)
|
||||
|
||||
def test_pickling(self):
|
||||
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||
self.assertRaises(NotImplementedError, pickle.dumps, self.gen, proto)
|
||||
|
||||
def test_53_bits_per_float(self):
|
||||
# This should pass whenever a C double has 53 bit precision.
|
||||
span = 2 ** 53
|
||||
cum = 0
|
||||
for i in range(100):
|
||||
cum |= int(self.gen.random() * span)
|
||||
self.assertEqual(cum, span-1)
|
||||
self.assertRaises(TypeError, getrandbits)
|
||||
self.assertRaises(TypeError, getrandbits, 1, 2)
|
||||
self.assertRaises(ValueError, getrandbits, -1)
|
||||
self.assertRaises(OverflowError, getrandbits, 1<<1000)
|
||||
self.assertRaises(ValueError, getrandbits, -1<<1000)
|
||||
self.assertRaises(TypeError, getrandbits, 10.1)
|
||||
|
||||
def test_bigrand(self):
|
||||
# The randrange routine should build-up the required number of bits
|
||||
@@ -546,6 +492,10 @@ class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
randrange(1000, step=100)
|
||||
with self.assertRaises(TypeError):
|
||||
randrange(1000, None, step=100)
|
||||
with self.assertRaises(TypeError):
|
||||
randrange(1000, step=MyIndex(1))
|
||||
with self.assertRaises(TypeError):
|
||||
randrange(1000, None, step=MyIndex(1))
|
||||
|
||||
def test_randbelow_logic(self, _log=log, int=int):
|
||||
# check bitcount transition points: 2**i and 2**(i+1)-1
|
||||
@@ -568,6 +518,116 @@ class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
self.assertEqual(k, numbits) # note the stronger assertion
|
||||
self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion
|
||||
|
||||
def test_randrange_index(self):
|
||||
randrange = self.gen.randrange
|
||||
self.assertIn(randrange(MyIndex(5)), range(5))
|
||||
self.assertIn(randrange(MyIndex(2), MyIndex(7)), range(2, 7))
|
||||
self.assertIn(randrange(MyIndex(5), MyIndex(15), MyIndex(2)), range(5, 15, 2))
|
||||
|
||||
def test_randint(self):
|
||||
randint = self.gen.randint
|
||||
self.assertIn(randint(2, 5), (2, 3, 4, 5))
|
||||
self.assertEqual(randint(2, 2), 2)
|
||||
self.assertIn(randint(MyIndex(2), MyIndex(5)), (2, 3, 4, 5))
|
||||
self.assertEqual(randint(MyIndex(2), MyIndex(2)), 2)
|
||||
|
||||
self.assertRaises(ValueError, randint, 5, 2)
|
||||
self.assertRaises(TypeError, randint)
|
||||
self.assertRaises(TypeError, randint, 2)
|
||||
self.assertRaises(TypeError, randint, 2, 5, 1)
|
||||
self.assertRaises(TypeError, randint, 2.0, 5)
|
||||
self.assertRaises(TypeError, randint, 2, 5.0)
|
||||
|
||||
def test_pickling(self):
|
||||
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||
state = pickle.dumps(self.gen, proto)
|
||||
origseq = [self.gen.random() for i in range(10)]
|
||||
newgen = pickle.loads(state)
|
||||
restoredseq = [newgen.random() for i in range(10)]
|
||||
self.assertEqual(origseq, restoredseq)
|
||||
|
||||
def test_bug_1727780(self):
|
||||
# verify that version-2-pickles can be loaded
|
||||
# fine, whether they are created on 32-bit or 64-bit
|
||||
# platforms, and that version-3-pickles load fine.
|
||||
files = [("randv2_32.pck", 780),
|
||||
("randv2_64.pck", 866),
|
||||
("randv3.pck", 343)]
|
||||
for file, value in files:
|
||||
with open(support.findfile(file),"rb") as f:
|
||||
r = pickle.load(f)
|
||||
self.assertEqual(int(r.random()*1000), value)
|
||||
|
||||
def test_bug_9025(self):
|
||||
# Had problem with an uneven distribution in int(n*random())
|
||||
# Verify the fix by checking that distributions fall within expectations.
|
||||
n = 100000
|
||||
randrange = self.gen.randrange
|
||||
k = sum(randrange(6755399441055744) % 3 == 2 for i in range(n))
|
||||
self.assertTrue(0.30 < k/n < .37, (k/n))
|
||||
|
||||
def test_randrange_bug_1590891(self):
|
||||
start = 1000000000000
|
||||
stop = -100000000000000000000
|
||||
step = -200
|
||||
x = self.gen.randrange(start, stop, step)
|
||||
self.assertTrue(stop < x <= start)
|
||||
self.assertEqual((x+stop)%step, 0)
|
||||
|
||||
def test_randbytes(self):
|
||||
# Verify ranges
|
||||
for n in range(1, 10):
|
||||
data = self.gen.randbytes(n)
|
||||
self.assertEqual(type(data), bytes)
|
||||
self.assertEqual(len(data), n)
|
||||
|
||||
self.assertEqual(self.gen.randbytes(0), b'')
|
||||
|
||||
# Verify argument checking
|
||||
self.assertRaises(TypeError, self.gen.randbytes)
|
||||
self.assertRaises(TypeError, self.gen.randbytes, 1, 2)
|
||||
self.assertRaises(ValueError, self.gen.randbytes, -1)
|
||||
self.assertRaises(OverflowError, self.gen.randbytes, 1<<1000)
|
||||
self.assertRaises((ValueError, OverflowError), self.gen.randbytes, -1<<1000)
|
||||
self.assertRaises(TypeError, self.gen.randbytes, 1.0)
|
||||
|
||||
def test_mu_sigma_default_args(self):
|
||||
self.assertIsInstance(self.gen.normalvariate(), float)
|
||||
self.assertIsInstance(self.gen.gauss(), float)
|
||||
|
||||
|
||||
try:
|
||||
random.SystemRandom().random()
|
||||
except NotImplementedError:
|
||||
SystemRandom_available = False
|
||||
else:
|
||||
SystemRandom_available = True
|
||||
|
||||
@unittest.skipUnless(SystemRandom_available, "random.SystemRandom not available")
|
||||
class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
gen = random.SystemRandom()
|
||||
|
||||
def test_autoseed(self):
|
||||
# Doesn't need to do anything except not fail
|
||||
self.gen.seed()
|
||||
|
||||
def test_saverestore(self):
|
||||
self.assertRaises(NotImplementedError, self.gen.getstate)
|
||||
self.assertRaises(NotImplementedError, self.gen.setstate, None)
|
||||
|
||||
def test_seedargs(self):
|
||||
# Doesn't need to do anything except not fail
|
||||
self.gen.seed(100)
|
||||
|
||||
def test_gauss(self):
|
||||
self.gen.gauss_next = None
|
||||
self.gen.seed(100)
|
||||
self.assertEqual(self.gen.gauss_next, None)
|
||||
|
||||
def test_pickling(self):
|
||||
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||
self.assertRaises(NotImplementedError, pickle.dumps, self.gen, proto)
|
||||
|
||||
|
||||
class TestRawMersenneTwister(unittest.TestCase):
|
||||
@test.support.cpython_only
|
||||
@@ -753,38 +813,6 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
seed = (1 << (10000 * 8)) - 1 # about 10K bytes
|
||||
self.gen.seed(seed)
|
||||
|
||||
def test_53_bits_per_float(self):
|
||||
# This should pass whenever a C double has 53 bit precision.
|
||||
span = 2 ** 53
|
||||
cum = 0
|
||||
for i in range(100):
|
||||
cum |= int(self.gen.random() * span)
|
||||
self.assertEqual(cum, span-1)
|
||||
|
||||
def test_bigrand(self):
|
||||
# The randrange routine should build-up the required number of bits
|
||||
# in stages so that all bit positions are active.
|
||||
span = 2 ** 500
|
||||
cum = 0
|
||||
for i in range(100):
|
||||
r = self.gen.randrange(span)
|
||||
self.assertTrue(0 <= r < span)
|
||||
cum |= r
|
||||
self.assertEqual(cum, span-1)
|
||||
|
||||
def test_bigrand_ranges(self):
|
||||
for i in [40,80, 160, 200, 211, 250, 375, 512, 550]:
|
||||
start = self.gen.randrange(2 ** (i-2))
|
||||
stop = self.gen.randrange(2 ** i)
|
||||
if stop <= start:
|
||||
continue
|
||||
self.assertTrue(start <= self.gen.randrange(start, stop) < stop)
|
||||
|
||||
def test_rangelimits(self):
|
||||
for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]:
|
||||
self.assertEqual(set(range(start,stop)),
|
||||
set([self.gen.randrange(start,stop) for i in range(100)]))
|
||||
|
||||
def test_getrandbits(self):
|
||||
super().test_getrandbits()
|
||||
|
||||
@@ -792,6 +820,25 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
self.gen.seed(1234567)
|
||||
self.assertEqual(self.gen.getrandbits(100),
|
||||
97904845777343510404718956115)
|
||||
self.gen.seed(1234567)
|
||||
self.assertEqual(self.gen.getrandbits(MyIndex(100)),
|
||||
97904845777343510404718956115)
|
||||
|
||||
def test_getrandbits_2G_bits(self):
|
||||
size = 2**31
|
||||
self.gen.seed(1234567)
|
||||
x = self.gen.getrandbits(size)
|
||||
self.assertEqual(x.bit_length(), size)
|
||||
self.assertEqual(x & (2**100-1), 890186470919986886340158459475)
|
||||
self.assertEqual(x >> (size-100), 1226514312032729439655761284440)
|
||||
|
||||
@support.bigmemtest(size=2**32, memuse=1/8+2/15, dry_run=False)
|
||||
def test_getrandbits_4G_bits(self, size):
|
||||
self.gen.seed(1234568)
|
||||
x = self.gen.getrandbits(size)
|
||||
self.assertEqual(x.bit_length(), size)
|
||||
self.assertEqual(x & (2**100-1), 287241425661104632871036099814)
|
||||
self.assertEqual(x >> (size-100), 739728759900339699429794460738)
|
||||
|
||||
def test_randrange_uses_getrandbits(self):
|
||||
# Verify use of getrandbits by randrange
|
||||
@@ -803,27 +850,6 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
self.assertEqual(self.gen.randrange(2**99),
|
||||
97904845777343510404718956115)
|
||||
|
||||
def test_randbelow_logic(self, _log=log, int=int):
|
||||
# check bitcount transition points: 2**i and 2**(i+1)-1
|
||||
# show that: k = int(1.001 + _log(n, 2))
|
||||
# is equal to or one greater than the number of bits in n
|
||||
for i in range(1, 1000):
|
||||
n = 1 << i # check an exact power of two
|
||||
numbits = i+1
|
||||
k = int(1.00001 + _log(n, 2))
|
||||
self.assertEqual(k, numbits)
|
||||
self.assertEqual(n, 2**(k-1))
|
||||
|
||||
n += n - 1 # check 1 below the next power of two
|
||||
k = int(1.00001 + _log(n, 2))
|
||||
self.assertIn(k, [numbits, numbits+1])
|
||||
self.assertTrue(2**k > n > 2**(k-2))
|
||||
|
||||
n -= n >> 15 # check a little farther below the next power of two
|
||||
k = int(1.00001 + _log(n, 2))
|
||||
self.assertEqual(k, numbits) # note the stronger assertion
|
||||
self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion
|
||||
|
||||
def test_randbelow_without_getrandbits(self):
|
||||
# Random._randbelow() can only use random() when the built-in one
|
||||
# has been overridden but no new getrandbits() method was supplied.
|
||||
@@ -858,14 +884,6 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
self.gen._randbelow_without_getrandbits(n, maxsize=maxsize)
|
||||
self.assertEqual(random_mock.call_count, 2)
|
||||
|
||||
def test_randrange_bug_1590891(self):
|
||||
start = 1000000000000
|
||||
stop = -100000000000000000000
|
||||
step = -200
|
||||
x = self.gen.randrange(start, stop, step)
|
||||
self.assertTrue(stop < x <= start)
|
||||
self.assertEqual((x+stop)%step, 0)
|
||||
|
||||
def test_choices_algorithms(self):
|
||||
# The various ways of specifying weights should produce the same results
|
||||
choices = self.gen.choices
|
||||
@@ -949,6 +967,14 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
self.assertEqual(self.gen.randbytes(n),
|
||||
gen2.getrandbits(n * 8).to_bytes(n, 'little'))
|
||||
|
||||
@support.bigmemtest(size=2**29, memuse=1+16/15, dry_run=False)
|
||||
def test_randbytes_256M(self, size):
|
||||
self.gen.seed(2849427419)
|
||||
x = self.gen.randbytes(size)
|
||||
self.assertEqual(len(x), size)
|
||||
self.assertEqual(x[:12].hex(), 'f6fd9ae63855ab91ea238b4f')
|
||||
self.assertEqual(x[-12:].hex(), '0e7af69a84ee99bf4a11becc')
|
||||
|
||||
def test_sample_counts_equivalence(self):
|
||||
# Test the documented strong equivalence to a sample with repeated elements.
|
||||
# We run this test on random.Random() which makes deterministic selections
|
||||
@@ -1081,6 +1107,7 @@ class TestDistributions(unittest.TestCase):
|
||||
B(n=1, p=-0.5) # Negative p
|
||||
with self.assertRaises(ValueError):
|
||||
B(n=1, p=1.5) # p > 1.0
|
||||
self.assertEqual(B(0, 0.5), 0) # n == 0
|
||||
self.assertEqual(B(10, 0.0), 0) # p == 0.0
|
||||
self.assertEqual(B(10, 1.0), 10) # p == 1.0
|
||||
self.assertTrue(B(1, 0.3) in {0, 1}) # n == 1 fast path
|
||||
@@ -1088,6 +1115,9 @@ class TestDistributions(unittest.TestCase):
|
||||
self.assertTrue(B(1, 0.0) in {0}) # n == 1 fast path
|
||||
self.assertTrue(B(1, 1.0) in {1}) # n == 1 fast path
|
||||
|
||||
# BG method very small p
|
||||
self.assertEqual(B(5, 1e-18), 0)
|
||||
|
||||
# BG method p <= 0.5 and n*p=1.25
|
||||
self.assertTrue(B(5, 0.25) in set(range(6)))
|
||||
|
||||
@@ -1266,6 +1296,13 @@ class TestDistributions(unittest.TestCase):
|
||||
|
||||
|
||||
class TestRandomSubclassing(unittest.TestCase):
|
||||
def test_random_subclass_with_kwargs(self):
|
||||
# SF bug #1486663 -- this used to erroneously raise a TypeError
|
||||
class Subclass(random.Random):
|
||||
def __init__(self, newarg=None):
|
||||
random.Random.__init__(self)
|
||||
Subclass(newarg=1)
|
||||
|
||||
def test_subclasses_overriding_methods(self):
|
||||
# Subclasses with an overridden random, but only the original
|
||||
# getrandbits method should not rely on getrandbits in for randrange,
|
||||
@@ -1386,5 +1423,48 @@ class TestModule(unittest.TestCase):
|
||||
support.wait_process(pid, exitcode=0)
|
||||
|
||||
|
||||
class CommandLineTest(unittest.TestCase):
|
||||
@support.force_not_colorized
|
||||
def test_parse_args(self):
|
||||
args, help_text = random._parse_args(shlex.split("--choice a b c"))
|
||||
self.assertEqual(args.choice, ["a", "b", "c"])
|
||||
self.assertStartsWith(help_text, "usage: ")
|
||||
|
||||
args, help_text = random._parse_args(shlex.split("--integer 5"))
|
||||
self.assertEqual(args.integer, 5)
|
||||
self.assertStartsWith(help_text, "usage: ")
|
||||
|
||||
args, help_text = random._parse_args(shlex.split("--float 2.5"))
|
||||
self.assertEqual(args.float, 2.5)
|
||||
self.assertStartsWith(help_text, "usage: ")
|
||||
|
||||
args, help_text = random._parse_args(shlex.split("a b c"))
|
||||
self.assertEqual(args.input, ["a", "b", "c"])
|
||||
self.assertStartsWith(help_text, "usage: ")
|
||||
|
||||
args, help_text = random._parse_args(shlex.split("5"))
|
||||
self.assertEqual(args.input, ["5"])
|
||||
self.assertStartsWith(help_text, "usage: ")
|
||||
|
||||
args, help_text = random._parse_args(shlex.split("2.5"))
|
||||
self.assertEqual(args.input, ["2.5"])
|
||||
self.assertStartsWith(help_text, "usage: ")
|
||||
|
||||
def test_main(self):
|
||||
for command, expected in [
|
||||
("--choice a b c", "b"),
|
||||
('"a b c"', "b"),
|
||||
("a b c", "b"),
|
||||
("--choice 'a a' 'b b' 'c c'", "b b"),
|
||||
("'a a' 'b b' 'c c'", "b b"),
|
||||
("--integer 5", 4),
|
||||
("5", 4),
|
||||
("--float 2.5", 2.1110546288126204),
|
||||
("2.5", 2.1110546288126204),
|
||||
]:
|
||||
random.seed(0)
|
||||
self.assertEqual(random.main(shlex.split(command)), expected)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user