Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python中随机数最后位数的分布_Python_Random - Fatal编程技术网

Python中随机数最后位数的分布

Python中随机数最后位数的分布,python,random,Python,Random,在Python中,有两种明显的方法可以生成从0到9的随机数字。可以生成一个介于0和1之间的随机浮点数,乘以10,然后向下取整。或者,可以使用random.randint方法 import random def random_digit_1(): return int(10 * random.random()) def random_digit_2(): return random.randint(0, 9) 我很好奇,如果一个人生成一个介于0和1之间的随机数,并保留最后一个

在Python中,有两种明显的方法可以生成从0到9的随机数字。可以生成一个介于0和1之间的随机浮点数,乘以10,然后向下取整。或者,可以使用
random.randint
方法

import random

def random_digit_1():
    return int(10 * random.random())

def random_digit_2():
    return random.randint(0, 9)
我很好奇,如果一个人生成一个介于0和1之间的随机数,并保留最后一个数字,会发生什么。我不一定期望分布是均匀的,但我发现结果相当令人惊讶

from random import random, seed
from collections import Counter

seed(0)
counts = Counter(int(str(random())[-1]) for _ in range(1_000_000))
print(counts)
输出:

Counter({1: 84206,
         5: 130245,
         3: 119433,
         6: 129835,
         8: 101488,
         2: 100861,
         9: 84796,
         4: 129088,
         7: 120048})
柱状图如下所示。请注意,0不会出现,因为尾部的零会被截断。但有人能解释为什么数字4、5和6比其他数字更常见吗?我曾经 Python3.6.10,但在Python3.8.0a4中的结果类似

这不是数字的“最后一位”。这是传递数字时字符串
str
给您的最后一位数字

当您在浮点上调用
str
时,Python会为您提供足够的数字,以便在字符串上调用
float
将为您提供原始浮点。为此,尾随1或9比其他数字更不必要,因为尾随1或9表示数字非常接近通过舍入该数字得到的值。很有可能没有其他浮点数更接近,如果是这样的话,可以在不牺牲
float(str(original_float))
行为的情况下丢弃该数字

如果
str
提供了足够的数字来精确表示参数,则最后一位数字几乎总是5,除非
random.random()
返回0.0,在这种情况下,最后一位数字将是0。(浮点只能表示,非整数二元有理数的最后一个非零十进制数字总是5。)输出也会非常长,看起来像

>>> import decimal, random
>>> print(decimal.Decimal(random.random()))
0.29711195452007921335990658917580731213092803955078125
这就是
str
不这样做的原因之一

如果
str
正好给了您17个有效数字(足以区分所有浮点值,但有时数字比需要的多),那么您看到的效果就会消失。尾随数字(包括0)几乎均匀分布


(另外,您忘记了
str
有时会返回科学记数法中的字符串,但这只是一个小影响,因为从
random.random()
)中获得浮点值的概率很低)

TL;DR您的示例实际上并没有看到最后一位数字。转换为基数10的有限二进制尾数的最后一位应始终为
0
5


请看下面的评论:

char*PyOS\u double\u到字符串(double val,
字符格式\u代码,
整数精度,
int标志,
int*类型)
{
字符格式[32];
Py_ssize_t bufsize;
char*buf;
int t,exp;
整数上限=0;
/*验证格式代码,并映射大小写*/
开关(格式\u代码){
// ...
案例'r':/*repr格式*/
/*提供的精度未使用,必须为0*/
如果(精度!=0){
PyErr_BadInternalCall();
返回NULL;
}
/*repr()精度(17位有效十进制数字)是
保证有足够精度的最小数
所以如果这个数字是以完全相同的二进制读回的
值被重新创建。这对于IEEE浮点是正确的
这是设计上的,而且碰巧也适用于所有其他现代企业
硬件*/
精度=17;
格式_代码='g';
打破
// ...
}
确认这一点:

53位有效位精度提供15到17位有效十进制数字精度(2-53≈ 1.11 × 10-16)。如果将最多15位有效数字的十进制字符串转换为IEEE 754双精度表示,然后再转换回具有相同位数的十进制字符串,则最终结果应与原始字符串匹配。如果将IEEE 754双精度数字转换为至少17位有效数字的十进制字符串t位,然后转换回双精度表示,最终结果必须与原始数字匹配。

因此,当我们使用
str
(或
repr
)时,我们只表示以10为基数的17位有效数字。这意味着一些浮点数将被截断。事实上,要获得准确的表示,您需要53位有效数字的精度!您可以通过以下方式验证:

>>> counts = Counter(
...     len(f"{random():.99f}".lstrip("0.").rstrip("0"))
...     for _ in range(1000000)
... )
>>> counts
Counter({53: 449833,
         52: 270000,
         51: 139796,
         50: 70341,
         49: 35030,
         48: 17507,
         47: 8610,
         46: 4405,
         45: 2231,
         44: 1120,
         43: 583,
         42: 272,
         41: 155,
         40: 60,
         39: 25,
         38: 13,
         37: 6,
         36: 5,
         35: 4,
         34: 3,
         32: 1})
>>> max(counts)
53
现在使用最大精度,这里是找到“最后一位”的正确方法:

因此,最后一个数字总是
5
(或者在极少数情况下,
0
),这是有意义的,因为:

2**0  == 1.0
2**-1 == 0.5
2**-2 == 0.25
2**-3 == 0.125
2**-4 == 0.0625
2**-5 == 0.03125
2**-6 == 0.015625
2**-7 == 0.0078125
2**-8 == 0.00390625
2**-9 == 0.001953125
...
2**-k == 0.[k-1 digits]5
所有尾数都是这些系数的部分和



注意:正如用户2357112所指出的,要查看的正确实现是和,但我将保留当前的实现,因为它在教学上更有趣。

这与Python中计算浮点数的字符串表示的方式有关。请参阅。如果使用十分之一的digi,您将获得更均匀的结果t(小数点后的第一位)而不是最后一位数字。我们以二进制表示形式存储浮点数(因为我们的内存也是二进制的)。
str
将其转换为基数-10,这必然会导致问题。例如,1位浮点数尾数
b0->1.0
b1->1.5
。“最后一位”将始终是
0
5
随机。随机范围(10)更为明显,IMHO。
随机。随机范围
(在引擎盖下调用
random.randrange
)是
随机
模块的一个后续添加,适用于不了解范围如何工作的人
2**0  == 1.0
2**-1 == 0.5
2**-2 == 0.25
2**-3 == 0.125
2**-4 == 0.0625
2**-5 == 0.03125
2**-6 == 0.015625
2**-7 == 0.0078125
2**-8 == 0.00390625
2**-9 == 0.001953125
...
2**-k == 0.[k-1 digits]5