# Generate uniform random point inside unit square.
import math
import random
def randrange(a, b):
return random.random() * (b - a) + a
# @brief Generate uniform random point inside unit square.
# @param mindist Minimum axial distance from center.
# @return 2-tuple float type.
def randunit2_1(mindist):
assert 0 <= mindist <= 1
while True:
x = randrange(-1, 1)
y = randrange(-1, 1)
if abs(x) >= mindist or abs(y) >= mindist:
break
return x, y
def randunit2_2(mindist):
assert 0 <= mindist <= 1
# @note Find a random point on the perimeter of a unit square.
# Use distance to select a random point along the vector from
# origin to the perimeter.
#
# The square root will bias result toward the perimeter where
# area is greater; prevents points 'bunching' near the center.
dist = math.sqrt(randrange(pow(mindist, 2), 1))
t, s = math.modf(randrange(0, 4))
x = 2*t - 1
y = s%2*2 - 1
if s < 2:
x, y = y, x
return x * dist, y * dist
# Main.
def unit_to_norm(x):
return x * 0.5 + 0.5
def grouper(iterable, n):
return zip(*[iter(iterable)] * n)
def show(n, f, d):
h = [0] * 9
for _ in range(n*9):
x, y = map(unit_to_norm, f(d))
i = math.floor(x * 3)
j = math.floor(y * 3)
k = j*3+i
assert 0 <= k < 9
h[k] += 1
print(f.__name__)
for x in grouper((x/n for x in h), 3):
print(' (', ', '.join(f'{y:.2f}' for y in x), ')', sep='')
n = 1000
d = 1/3
show(n, randunit2_1, d)
show(n, randunit2_2, d)
IyBHZW5lcmF0ZSB1bmlmb3JtIHJhbmRvbSBwb2ludCBpbnNpZGUgdW5pdCBzcXVhcmUuCgppbXBvcnQgbWF0aAppbXBvcnQgcmFuZG9tCgpkZWYgcmFuZHJhbmdlKGEsIGIpOgogICAgcmV0dXJuIHJhbmRvbS5yYW5kb20oKSAqIChiIC0gYSkgKyBhCgojIEBicmllZiBHZW5lcmF0ZSB1bmlmb3JtIHJhbmRvbSBwb2ludCBpbnNpZGUgdW5pdCBzcXVhcmUuCiMgQHBhcmFtICBtaW5kaXN0ICBNaW5pbXVtIGF4aWFsIGRpc3RhbmNlIGZyb20gY2VudGVyLgojIEByZXR1cm4gMi10dXBsZSBmbG9hdCB0eXBlLgoKZGVmIHJhbmR1bml0Ml8xKG1pbmRpc3QpOgogICAgYXNzZXJ0IDAgPD0gbWluZGlzdCA8PSAxCiAgICB3aGlsZSBUcnVlOgogICAgICAgIHggPSByYW5kcmFuZ2UoLTEsIDEpCiAgICAgICAgeSA9IHJhbmRyYW5nZSgtMSwgMSkKICAgICAgICBpZiBhYnMoeCkgPj0gbWluZGlzdCBvciBhYnMoeSkgPj0gbWluZGlzdDoKICAgICAgICAgICAgYnJlYWsKICAgIHJldHVybiB4LCB5CgpkZWYgcmFuZHVuaXQyXzIobWluZGlzdCk6CiAgICBhc3NlcnQgMCA8PSBtaW5kaXN0IDw9IDEKCiAgICAjIEBub3RlIEZpbmQgYSByYW5kb20gcG9pbnQgb24gdGhlIHBlcmltZXRlciBvZiBhIHVuaXQgc3F1YXJlLgogICAgIyBVc2UgZGlzdGFuY2UgdG8gc2VsZWN0IGEgcmFuZG9tIHBvaW50IGFsb25nIHRoZSB2ZWN0b3IgZnJvbQogICAgIyBvcmlnaW4gdG8gdGhlIHBlcmltZXRlci4KICAgICMKICAgICMgVGhlIHNxdWFyZSByb290IHdpbGwgYmlhcyByZXN1bHQgdG93YXJkIHRoZSBwZXJpbWV0ZXIgd2hlcmUKICAgICMgYXJlYSBpcyBncmVhdGVyOyBwcmV2ZW50cyBwb2ludHMgJ2J1bmNoaW5nJyBuZWFyIHRoZSBjZW50ZXIuCgogICAgZGlzdCA9IG1hdGguc3FydChyYW5kcmFuZ2UocG93KG1pbmRpc3QsIDIpLCAxKSkKICAgIHQsIHMgPSBtYXRoLm1vZGYocmFuZHJhbmdlKDAsIDQpKQogICAgeCA9IDIqdCAtIDEKICAgIHkgPSBzJTIqMiAtIDEKICAgIGlmIHMgPCAyOgogICAgICAgIHgsIHkgPSB5LCB4CiAgICByZXR1cm4geCAqIGRpc3QsIHkgKiBkaXN0CgojIE1haW4uCgpkZWYgdW5pdF90b19ub3JtKHgpOgogICAgcmV0dXJuIHggKiAwLjUgKyAwLjUKCmRlZiBncm91cGVyKGl0ZXJhYmxlLCBuKToKICAgIHJldHVybiB6aXAoKltpdGVyKGl0ZXJhYmxlKV0gKiBuKQoKZGVmIHNob3cobiwgZiwgZCk6CiAgICBoID0gWzBdICogOQogICAgZm9yIF8gaW4gcmFuZ2Uobio5KToKICAgICAgICB4LCB5ID0gbWFwKHVuaXRfdG9fbm9ybSwgZihkKSkKICAgICAgICBpID0gbWF0aC5mbG9vcih4ICogMykKICAgICAgICBqID0gbWF0aC5mbG9vcih5ICogMykKICAgICAgICBrID0gaiozK2kKICAgICAgICBhc3NlcnQgMCA8PSBrIDwgOQogICAgICAgIGhba10gKz0gMQogICAgcHJpbnQoZi5fX25hbWVfXykKICAgIGZvciB4IGluIGdyb3VwZXIoKHgvbiBmb3IgeCBpbiBoKSwgMyk6CiAgICAgICAgcHJpbnQoJyAoJywgJywgJy5qb2luKGYne3k6LjJmfScgZm9yIHkgaW4geCksICcpJywgc2VwPScnKQoKbiA9IDEwMDAKZCA9IDEvMwpzaG93KG4sIHJhbmR1bml0Ml8xLCBkKQpzaG93KG4sIHJhbmR1bml0Ml8yLCBkKQ==
randunit2_1
(1.14, 1.09, 1.12)
(1.08, 0.00, 1.14)
(1.17, 1.14, 1.11)
randunit2_2
(1.10, 1.13, 1.09)
(1.14, 0.00, 1.13)
(1.11, 1.15, 1.15)