use*_*923 21 python random floating-point
我正在尝试生成介于0.1和1.0之间的随机数.我们无法使用,rand.randint
因为它返回整数.我们也试过了random.uniform(0.1,1.0)
,但它返回的值> = 0.1且<1.0,我们不能使用它,因为我们的搜索也包含1.0.
有人对这个问题有所了解吗?
Elm*_*ise 18
你想要随机数如何"准确"?如果您对10位十进制数字感到满意,则可以舍入random.uniform(0.1, 1.0)
到10位数.这样你将包括0.1
和1.0
:
round(random.uniform(0.1, 1.0), 10)
Run Code Online (Sandbox Code Playgroud)
确切地说,0.1
并且1.0
只有一半的概率与之间的任何其他数字相比,当然,你会丢失所有随机数,这些数字仅在10位数之后有所不同.
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()
Run Code Online (Sandbox Code Playgroud)
where 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
Run Code Online (Sandbox Code Playgroud)
它允许在不丢失精度的情况下[0.1, 1]
使用(包括)
查找随机数randint()
:
n, m = 7205759403792794, 2 ** N
f = randint(n, m) / m
Run Code Online (Sandbox Code Playgroud)
randint(n, m)
返回[n, m]
(包括)中的随机整数,因此上述方法可能会返回所有浮点数[0.1, 1]
.
另一种方法是找到最小x
,从而x > 1
与用途:
f = uniform(.1, x)
while f > 1:
f = uniform(.1, x)
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
两种解决方案都保持随机分布的均匀性(无歪斜).
你可以这样做:
>>> 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)]
Run Code Online (Sandbox Code Playgroud)
或者,使用numpy的制服:
np.random.uniform(low=0.1, high=np.nextafter(1,2), size=1)
Run Code Online (Sandbox Code Playgroud)
nextafter将生成平台特定的下一个可表示的浮动指向数字朝向一个方向.使用numpy的random.uniform是有利的,因为它不包含上限是明确的.
编辑
Mark Dickinson的评论似乎是正确的:Numpy的文档对于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
Run Code Online (Sandbox Code Playgroud)
在这个有限的范围内,结果也不均匀:
>>> 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
Run Code Online (Sandbox Code Playgroud)
然而,结合JF Sebastian和Mark Dickinson的评论,我认为这有效:
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)]
Run Code Online (Sandbox Code Playgroud)
如果在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))
Run Code Online (Sandbox Code Playgroud)
它产生所需的均匀分布,包括端点:
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
Run Code Online (Sandbox Code Playgroud)
在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()
Run Code Online (Sandbox Code Playgroud)
产量
归档时间: |
|
查看次数: |
22783 次 |
最近记录: |