将整数拆分为浮点数

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)

期望的输出:

  • 数字列表,
  • 浮点数(2 dp),
  • 不平衡。

所需输出示例:

[10.50, 22.98, 13.23, 40.33, 12.96]
Run Code Online (Sandbox Code Playgroud)

pjs*_*pjs 5

如果您统一从第一个的完整范围、第二个的剩余范围、第三个的剩余范围等开始生成值,则每次获得的值有 50% 的机会大于一半剩余范围。这会导致系统偏差 \xe2\x80\x94 平均而言,较早的值往往大于较晚的值。有一个简单的算法可以避免这种情况并为所有位置获得相同的分布:

\n
    \n
  1. 生成一个包含0和最大值的列表,然后附加n-1个值,这些值都均匀分布在0和最大值之间;
  2. \n
  3. 对列表进行排序;和
  4. \n
  5. 计算排序列表中相邻值对之间的差异。
  6. \n
\n

根据定义,结果将累加到最大值,因为它们是 0 和最大值之间的间隔长度。大差距或小差距同样可能出现在任何对之间,从而保证相同的分布(在 PRNG 实际上是均匀的范围内)。

\n

我采用了按比例放大 100 并返回以得到两位小数的想法。这是代码:

\n
import 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)(不包括端点)进行采样而无需替换来完成。以下实现非常简单,并且可能比上面基于循环的实现更具可读性:

\n
import 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)\n

n该版本在处理相对于 较大的值时没有问题x

\n
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

跟进

\n

我尝试split(100,5)为我的解决方案和 Gabriel d\'Agosto 提供的答案生成 10,000 个重复,这样我就可以并排显示生成的第一个到第五个值的结果分布直方图。我的解决方案的结果是:

\n

并排直方图显示生成结果的相同分布,与顺序无关

\n

正如您所看到的,结果的分布与生成顺序无关。

\n

我无法使用其他答案生成 10k 复制,该答案在几十次迭代内失败并显示错误消息ValueError: empty range for randrange() (1, 1, 0)。这种方法很有可能用完该范围,因此算法没有足够的空间来完成生成所有值。

\n