Dan*_*l99 1 python random floating-point python-3.x
目标:分成随机的小数点100
后两位数字。5
到目前为止,我可以模拟任意数量的划分。
然而,这些只是整数并且是“平衡的”,因为它们的值彼此相同或接近。因此,输出总是相同的。
代码:
def split(x, n):
if(x < n):
print(-1)
elif (x % n == 0):
for i in range(n):
print(x//n, end =" ")
else:
zp = n - (x % n)
pp = x//n
for i in range(n):
if(i>= zp):
print(pp + 1, end =" ")
else:
print(pp, end =" ")
split(100, 5)
>>> 20 20 20 20 20
Run Code Online (Sandbox Code Playgroud)
期望的输出:
所需输出示例:
[10.50, 22.98, 13.23, 40.33, 12.96]
Run Code Online (Sandbox Code Playgroud)
如果您统一从第一个的完整范围、第二个的剩余范围、第三个的剩余范围等开始生成值,则每次获得的值有 50% 的机会大于一半剩余范围。这会导致系统偏差 \xe2\x80\x94 平均而言,较早的值往往大于较晚的值。有一个简单的算法可以避免这种情况并为所有位置获得相同的分布:
\n根据定义,结果将累加到最大值,因为它们是 0 和最大值之间的间隔长度。大差距或小差距同样可能出现在任何对之间,从而保证相同的分布(在 PRNG 实际上是均匀的范围内)。
\n我采用了按比例放大 100 并返回以得到两位小数的想法。这是代码:
\nimport random\nimport sys\n\ndef split(x, n, decimal=2):\n assert (decimal >= 0), "Number of decimals must be positive"\n\n scale_factor = 10**decimal\n x *= scale_factor\n assert (n <= x), "Quantity exceeds range"\n\n numbers = [0, x]\n for _ in range(n - 1):\n numbers.append(random.randint(1, x))\n numbers.sort()\n\n return [(numbers[i] - numbers[i-1]) / scale_factor for i in range(1, n+1)]\n
Run Code Online (Sandbox Code Playgroud)\n其产生的结果例如
\n[10.82, 12.97, 17.92, 39.46, 18.83]\n[25.99, 21.35, 29.12, 8.13, 15.41]\n[5.51, 4.28, 69.59, 9.62, 11.0]\n[21.39, 20.96, 11.25, 15.07, 31.33]\n
Run Code Online (Sandbox Code Playgroud)\n如果要确保结果中不存在零,则需要确保随机生成的值集中不存在重复项。这可以通过对范围 (0,x)(不包括端点)进行采样而无需替换来完成。以下实现非常简单,并且可能比上面基于循环的实现更具可读性:
\nimport random\nimport sys\n\ndef split(x, n, decimal=2):\n assert (decimal >= 0), "Number of decimals must be positive"\n\n scale_factor = 10**decimal\n x *= scale_factor\n assert (n <= x), "Quantity exceeds range"\n\n numbers = [0, x] + random.sample(range(1, x), n - 1)\n numbers.sort()\n return [(numbers[i] - numbers[i-1]) / scale_factor for i in range(1, n+1)]\n
Run Code Online (Sandbox Code Playgroud)\nn
该版本在处理相对于 较大的值时没有问题x
:
split(100, 20) # [6.98,4.53,23.66,2.84,2.53,2.81,12.86,0.39,3.05,11.19,3.21,2.56,1.4,1.67,3.13,1.76,7.21,0.23,1.52,6.47]\nsplit(1, 5, 1) # [0.1,0.2,0.1,0.3,0.3]\nsplit(1, 10, 1) # [0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1]\n
Run Code Online (Sandbox Code Playgroud)\n我尝试split(100,5)
为我的解决方案和 Gabriel d\'Agosto 提供的答案生成 10,000 个重复,这样我就可以并排显示生成的第一个到第五个值的结果分布直方图。我的解决方案的结果是:
正如您所看到的,结果的分布与生成顺序无关。
\n我无法使用其他答案生成 10k 复制,该答案在几十次迭代内失败并显示错误消息ValueError: empty range for randrange() (1, 1, 0)
。这种方法很有可能用完该范围,因此算法没有足够的空间来完成生成所有值。
归档时间: |
|
查看次数: |
269 次 |
最近记录: |