有关Python课程的介绍,我正在考虑在Python中生成随机浮点数,并且我已经看到了标准的推荐代码
import random
lower = 5
upper = 10
range_width = upper - lower
x = random.random() * range_width + lower
从5到10但不包括10的随机浮点。
在我看来,可以通过以下方式实现同样的效果:
import random
x = random.randrange(5, 10) + random.random()
因为那样会给出5,6,7,8或9的整数,然后用十进制表示。
我的问题是第二个代码是否会提供完全均匀的概率分布,还是不能保持第一个版本的完全随机性?
答案 0 :(得分:6)
根据documentation,然后是random()
确实是一个统一的分布。
random()
,它在半开放范围[0.0,1.0]内均匀生成随机浮点数。 Python使用Mersenne Twister作为核心生成器。
因此两个代码示例都应该没问题。要缩短代码,您同样可以:
random.uniform(5, 10)
请注意,uniform(a, b)
只是a + (b - a) * random()
,因此与您的第一个示例相同。
第二个示例取决于您正在使用的Python版本。
3.2 randrange()
之前可能会产生略微不均匀的分布。
答案 1 :(得分:2)
有区别。你的第二种方法在理论上是优越的,尽管在实践中它只对大范围有用。实际上,这两种方法都会给你一个统一的分布。但只有第二种方法可以返回范围内可表示为浮点数的所有值。
由于你的范围很小,所以没有明显的区别。但仍然存在是的差异,您可以通过考虑更大的范围来看到。如果取0到1之间的随机实数,则会得到具有给定位数的浮点表示。现在假设您的范围是2**32
的顺序。通过将原始随机数乘以此范围,您将在结果中丢失32位精度。换句话说,此方法可以返回的值之间存在间隙。当你乘以4时,间隙仍然存在:你丢失了原始随机数的两个最低有效位。
答案 2 :(得分:1)
两种方法可以给出不同的结果,但你只会注意到相当极端情况(范围非常宽)的区别。例如,如果您在0
和2/sys.float_info.epsilon
之间生成随机数(9007199254740992.0
,或者稍微超过9 quintillion),您会注意到使用乘法的版本永远不会给你任何数字浮点数小数。如果将最大界限增加到4/sys.float_info.epsilon
,则不会得到任何奇数整数,只有偶数整数。那是因为Python使用的64位浮点类型没有足够的精度来表示该范围上端的所有整数,并且它试图保持均匀分布(因此它省略了小的奇数整数和小数值,即使这些可以在范围的一部分中表示。)
计算的第二个版本将为生成的较小随机数提供额外的精度。例如,如果您在0
和2/sys.float_info.epsilon
之间生成数字并且randrange
调用返回0
,则可以使用random
调用的完整精度在数字中添加小数部分。另一方面,如果randrange
返回范围(2/sys.float_info.epsilon - 1
)中的最大数字,则将使用该分数的精度(该数字将舍入到最接近的整数而没有任何小数部分剩余的)。
添加小数值也无法帮助您处理对于每个要表示的整数而言过大的范围。如果randrange
仅返回偶数,则添加分数通常不会出现奇数(它可以在范围的某些部分,但不能用于其他部分,并且分布可能非常不均匀)。即使对于可以表示所有整数的范围,出现的特定浮点数的几率也不会完全一致,因为可以更精确地表示较小的数字。较大但不精确的数字将比较小但更准确的数字更常见。