Генерировать случайное число от 0,1 до 1,0. питон
Я пытаюсь создать случайное число от 0,1 до 1,0.
Мы не можем использовать rand.randint
, потому что он возвращает целые числа.
Мы также попробовали random.uniform(0.1,1.0)
, но он возвращает значение >= 0,1 и < 1.0, мы не можем использовать это, потому что наш поиск включает также 1.0.
У кого-то еще есть идея для этой проблемы?
Ответы
Ответ 1
Как "точные" вам нужны ваши случайные числа? Если вы довольны, скажем, 10 десятичными знаками, вы можете просто округлить random.uniform(0.1, 1.0)
до 10 цифр. Таким образом вы будете включать как 0.1
, так и 1.0
:
round(random.uniform(0.1, 1.0), 10)
Если быть точным, 0.1
и 1.0
будут иметь только половину вероятности по сравнению с любым другим числом между ними, и, конечно же, вы потеряете все случайные числа, которые отличаются только после 10 цифр.
Ответ 2
Random.uniform()
просто:
def uniform(self, a, b):
"Get a random number in the range [a, b) or [a, b] depending on rounding."
return a + (b-a) * self.random()
где self.random()
возвращает случайное число в диапазоне [0.0, 1.0)
.
Python (как и многие другие языки) использует плавающий
точка, чтобы представлять реальную
номера. Как представлен 0.1
, подробно описан в
документы:
from __future__ import division
BPF = 53 # assume IEEE 754 double-precision binary floating-point format
N = BPF + 3
assert 0.1 == 7205759403792794 / 2 ** N
Это позволяет найти случайное число в [0.1, 1]
(включительно), используя
randint()
без потери точности:
n, m = 7205759403792794, 2 ** N
f = randint(n, m) / m
randint(n, m)
возвращает случайное целое число в [n, m]
(включительно)
поэтому вышеупомянутый метод может потенциально возвращать все плавающие точки
числа в [0.1, 1]
.
Альтернативой является найти наименьший x
такой, что x > 1
и использовать:
f = uniform(.1, x)
while f > 1:
f = uniform(.1, x)
x
должно быть наименьшим значением, чтобы избежать потери точности и
уменьшите количество вызовов до uniform()
например:
import sys
# from itertools import count
# decimal.Decimal(1).next_plus() analog
# x = next(x for i in count(1) for x in [(2**BPF + i) / 2**BPF] if x > 1)
x = 1 + sys.float_info.epsilon
Оба решения сохраняют равномерность случайного распределения (нет перекоса).
Ответ 3
Вы можете сделать это:
>>> import numpy as np
>>> a=.1
>>> b=np.nextafter(1,2)
>>> print(b)
1.0000000000000002
>>> [a+(b-a)*random.random() for i in range(10)]
или, используйте numpy uniform:
np.random.uniform(low=0.1, high=np.nextafter(1,2), size=1)
nextafter создаст конкретное для платформы следующее отображаемое число с плавающей запятой в направлении. Использование numpy random.uniform выгодно, потому что недвусмысленно, что оно не включает верхнюю границу.
Изменить
Похоже, что комментарии Марка Дикинсона верны: Документация по номеру неверна в отношении верхней границы к random.uniform включительно или нет.
Документация Numpy содержит All values generated will be less than high.
Это легко опровергнуть:
>>> low=1.0
>>> high=1.0+2**-49
>>> a=np.random.uniform(low=low, high=high, size=10000)
>>> len(np.where(a==high)[0])
640
В этом ограниченном диапазоне результат равен единице:
>>> for e in sorted(set(a)):
... print('{:.16e}: {}'.format(e,len(np.where(a==e)[0])))
...
1.0000000000000000e+00: 652
1.0000000000000002e+00: 1215
1.0000000000000004e+00: 1249
1.0000000000000007e+00: 1288
1.0000000000000009e+00: 1245
1.0000000000000011e+00: 1241
1.0000000000000013e+00: 1228
1.0000000000000016e+00: 1242
1.0000000000000018e+00: 640
Однако, комментируя комментарии Ю. Ф. Себастьяна и Марка Дикинсона, я думаю, что это работает:
import numpy as np
import random
def rand_range(low=0,high=1,size=1):
a=np.nextafter(low,float('-inf'))
b=np.nextafter(high,float('inf'))
def r():
def rn():
return a+(b-a)*random.random()
_rtr=rn()
while _rtr > high:
_rtr=rn()
if _rtr<low:
_rtr=low
return _rtr
return [r() for i in range(size)]
Если вы запускаете с минимальным разбросом значений в комментарии Mark, чтобы было очень мало отдельных значений с плавающей запятой:
l,h=1,1+2**-48
s=10000
rands=rand_range(l,h,s)
se=sorted(set(rands))
if len(se)<25:
for i,e in enumerate(se,1):
c=rands.count(e)
note=''
if e==l: note='low value end point'
if e==h: note='high value end point'
print ('{:>2} {:.16e} {:,}, {:.4%} {}'.format(i, e, c, c/s,note))
Получает желаемое равномерное распределение, включая конечные точки:
1 1.0000000000000000e+00 589, 5.8900% low value end point
2 1.0000000000000002e+00 544, 5.4400%
3 1.0000000000000004e+00 612, 6.1200%
4 1.0000000000000007e+00 569, 5.6900%
5 1.0000000000000009e+00 593, 5.9300%
6 1.0000000000000011e+00 580, 5.8000%
7 1.0000000000000013e+00 565, 5.6500%
8 1.0000000000000016e+00 584, 5.8400%
9 1.0000000000000018e+00 603, 6.0300%
10 1.0000000000000020e+00 589, 5.8900%
11 1.0000000000000022e+00 597, 5.9700%
12 1.0000000000000024e+00 591, 5.9100%
13 1.0000000000000027e+00 572, 5.7200%
14 1.0000000000000029e+00 619, 6.1900%
15 1.0000000000000031e+00 593, 5.9300%
16 1.0000000000000033e+00 592, 5.9200%
17 1.0000000000000036e+00 608, 6.0800% high value end point
В отношении значений, запрошенных OP, он также создает равномерное распределение:
import matplotlib.pyplot as plt
l,h=.1,1
s=10000
bin_count=20
rands=rand_range(l,h,s)
count, bins, ignored = plt.hist(np.array(rands),bin_count)
plt.plot(bins, np.ones_like(bins)*s/bin_count, linewidth=2, color='r')
plt.show()
Выход
![uniform]()
Ответ 4
С информацией, которую вы предоставили (включая комментарии до сих пор), я все еще не понимаю, как университет собирается протестировать вашу программу, так что будет иметь значение, если появится 1.0 или нет. (Я имею в виду, если вам нужно создавать случайные поплавки, как они могут потребовать, чтобы появилось какое-то определенное значение?)
ОК, поэтому отбросьте сумасшествие ваших требований:
Тот факт, что нижняя граница ваших случайных поплавков выше 0, дает вам изящно элегантный способ использования random.random
, который гарантирует возвращаемые значения в интервале [0.0, 1.0]: просто продолжайте звонить random.random
, бросая от любых значений менее 0,1, кроме 0,0. Если вы действительно получаете 0.0, верните 1.0 вместо этого.
Так что-то вроде
from random import random
def myRandom():
while True:
r = random()
if r >= 0.1:
return r
if r == 0.0:
return 1.0
Ответ 5
Вы можете использовать random.randint просто, выполнив этот трюк:
>>> float(random.randint(1000,10000)) / 10000
0.4362
если вы хотите больше десятичных знаков, просто измените интервал на:
(1000 10000) 4 цифры
(10000 100 000) 5 цифр
и т.д.
Ответ 6
Вы не можете использовать random.random()
? Это дает число от 0.0 до 1.0, хотя вы можете легко настроить способ обойти это.
import random
def randomForMe():
number = random.random()
number = round(number, 1)
if (number == 0):
number = 0.1
Этот код даст вам число от 0,1 до 1,0 включительно (0,1 и 1,0 - оба возможных решения). Надеюсь, это поможет.
* Я предположил, что вы только хотели числа на десятое место. Если вы хотите, чтобы он был другим, где я набрал round(number, 1)
, измените 1
на 2
на сотые, 3
на тысячные и т.д.
Ответ 7
Стандартным способом было бы random.random() * 0.9 + 0.1
(random.uniform()
внутренне делает именно это). Это вернет числа от 0,1 до 1,0 без верхней границы.
Но подождите! 0.1 (aka ¹/₁₀) не имеет четкого двоичного представления (как ⅓ в десятичной форме)! Таким образом, вы все равно не получите истинный 0,1, просто потому, что компьютер не может представлять его внутренне. Извините; -)
Ответ 8
Согласно документации Python 3.0 :
random. равномерное (a, b) Возвращает случайное число N с плавающей запятой, такое, что a <= N <= b для a <= b и b <= N <= a для b < а.
Таким образом, random.uniform()
действительно включает верхний предел, по крайней мере, на Python 3.0.
EDIT: Как указано в @Blender, документация для Python 3.0, по-видимому, несовместима с исходным кодом в этой точке.
EDIT 2: Как отметил @MarkDickinson, я непреднамеренно связал с документацией Python 3.0, а не последнюю документацию Python 3 здесь, которая читается следующим образом:
случайный. единообразный (a, b) Возвращает случайное число с плавающей запятой N такое что a <= N <= b дл <= b и b <= N <= a для b < а.
Конечная точка значение b может или не может быть включено в диапазон в зависимости от округление с плавающей запятой в уравнении a + (b-a) * random().
Ответ 9
Try random.randint(1, 10)/100.0