【问题标题】:Random rounding to integer in PythonPython中随机舍入为整数
【发布时间】:2013-09-27 08:16:30
【问题描述】:

我正在寻找一种方法,根据从小数点后的数字得出的概率将浮点数向上或向下舍入到下一个整数。例如,浮点数 6.1 可以四舍五入为 6 和 7。四舍五入为 7 的概率为 0.1,四舍五入为 6 的概率为 1-0.1。所以如果我无限次地运行这个舍入实验,所有整数结果的平均值应该又是 6.1。我不知道这样的过程是否有名称,以及 Python 中是否已经存在并实现了函数。 当然,如果也可以四舍五入到例如,那将是非常好的。 2 位小数相同。

这有意义吗?有什么想法吗?

【问题讨论】:

  • 我看不出这项努力有什么意义(-: - 但这是可能的;将您的有效数字作为整数并乘以 numpy.random.rand() 进行我猜的舍入决定。
  • 这样的程序有一个名称:随机四舍五入,请参阅:en.wikipedia.org/wiki/Rounding#Stochastic_rounding

标签: python integer probability rounding


【解决方案1】:

您要查找的概率是x-int(x)

要以这种概率进行采样,请执行random.random() < x-int(x)

import random
import math
import numpy as np

def prob_round(x):
    sign = np.sign(x)
    x = abs(x)
    is_up = random.random() < x-int(x)
    round_func = math.ceil if is_up else math.floor
    return sign * round_func(x)

x = 6.1
sum( prob_round(x) for i in range(100) ) / 100.
=> 6.12

编辑:添加可选的prec 参数:

def prob_round(x, prec = 0):
    fixup = np.sign(x) * 10**prec
    x *= fixup
    is_up = random.random() < x-int(x)
    round_func = math.ceil if is_up else math.floor
    return round_func(x) / fixup

x = 8.33333333
[ prob_round(x, prec = 2) for i in range(10) ]
=> [8.3399999999999999,
 8.3300000000000001,
 8.3399999999999999,
 8.3300000000000001,
 8.3300000000000001,
 8.3300000000000001,
 8.3300000000000001,
 8.3300000000000001,
 8.3399999999999999,
 8.3399999999999999]

【讨论】:

  • 这个可以不用分支实现吗?
  • @étale-cohomology,当然。你可以这样做:math.floor(x) + (random.random() &lt; x-int(x))。哪个版本更具可读性是有争议的。
【解决方案2】:

这是一个很好的单线。通过使用 floor 函数,只有在 0 和 1 之间的随机数足以将其提升到下一个最高整数时,它才会被四舍五入。此方法同样适用于正数和负数。

def probabilistic_round(x):
    return int(math.floor(x + random.random()))

考虑负输入x = -2.25 的情况。 75% 的时间随机数将大于或等于 0.25,在这种情况下,地板函数将导致 -2 为答案。其他 25% 的时间该数字将向下舍入为 -3。

要四舍五入到不同的小数位,可以修改如下:

def probabilistic_round(x, decimal_places=0):
    factor = 10.0**decimal_places
    return int(math.floor(x*factor + random.random()))/factor

【讨论】:

    【解决方案3】:

    对非负 x 执行此操作的最简洁方法是:

    int(x + random.random())
    

    如果例如x == 6.1,那么random.random() 有 10% 的可能性会大到足以生成x + random.random() &gt;= 7

    注意如果x == 6,那么这个表达式保证返回6,因为random.random()总是在[0, 1)范围内。

    更新:此方法仅适用于非负输入。有关适用于负数的解决方案,请参阅 Chris Locke 的回答。

    【讨论】:

      【解决方案4】:

      要将正值四舍五入为整数,您可以非常简洁地执行此操作:

      x = int(x) + (random.random() < x - int(x))
      

      这是因为 Python 的 bool 类型是 int 的子类。 True 的值等于 1,False 的值等于 0。

      【讨论】:

        【解决方案5】:

        我还根据random的二项式函数和shx2已经提供的代码想出了一个解决方案:

        def prob_round(x, prec = 0):
            fixup = np.sign(x) * 10**prec
            x *= fixup 
            round_func = int(x) + np.random.binomial(1,x-int(x))
            return round_func/fixup
        

        【讨论】:

          【解决方案6】:

          这里有一个简单的方法:

          x = round(random.random()*100)
          

          *100 位表示 1 到 100。
          如果*200,表示1到200。

          【讨论】:

            猜你喜欢
            • 2020-10-01
            • 2021-05-25
            • 1970-01-01
            • 2011-11-15
            • 2011-11-14
            • 2014-05-21
            • 1970-01-01
            • 1970-01-01
            • 2022-08-18
            相关资源
            最近更新 更多