Memory 为什么是;“随机”;从内存插入的数字通常非常大?

Memory 为什么是;“随机”;从内存插入的数字通常非常大?,memory,floating-point,double,random-access,Memory,Floating Point,Double,Random Access,有时在开发例如C代码的过程中,您可能会意外地将数组索引到其最后一个元素之外,从而导致读取本质上是“随机”的内存块。我经常使用doubles数组,并注意到当这种情况发生时,从“随机”内存生成的double通常非常大,如大于1e+300。我想知道这是为什么 如果用于解释double的64位真的是随机的,我会期望double的指数从0到308(忽略指数符号),这是由于浮点数在内存中使用科学(指数)表示法的方式。当然,内存中随机选择的位的值本身并不是随机分布的,而是对应于任何进程设置这些值的某种有意义的

有时在开发例如C代码的过程中,您可能会意外地将数组索引到其最后一个元素之外,从而导致读取本质上是“随机”的内存块。我经常使用
double
s数组,并注意到当这种情况发生时,从“随机”内存生成的
double
通常非常大,如大于
1e+300
。我想知道这是为什么

如果用于解释
double
的64位真的是随机的,我会期望
double
的指数从
0
308
(忽略指数符号),这是由于浮点数在内存中使用科学(指数)表示法的方式。当然,内存中随机选择的位的值本身并不是随机分布的,而是对应于任何进程设置这些值的某种有意义的状态

为了研究这种影响,我编写了以下Python 3脚本,它绘制了从“随机”但未使用的内存中真正随机生成的
double
s和
double
s的分布:

import random,struct
将numpy作为np导入
将matplotlib.pyplot作为plt导入
N=10000
def随机_浮动(N=1):
返回np.array(struct.unpack('d'*N,字节)(random.randrange(256)表示范围(8*N))内的uuu)
def exp_hist(a,标签=无):
a=a[~np.isnan(a)]
a=a[~np.isinf(a)]
a=a[a!=0]
如果len(a)==0:
打印('仅限零!')
返回
a=np.abs(np.log10(np.abs(a)))
plt.hist(a,范围=(0350),密度=真,α=0.8,标签=标签)
#由均匀随机位生成的浮点
a=随机浮点数(N)
经验历史(a,“随机”)
#从内存内容生成的浮动
a=np.空(N)
经验历史(一种“记忆”)
plt.xlabel('指数')
plt.legend()
plt.savefig('plot.png')
运行此脚本的典型结果如下所示:

真正随机生成的
double
s的指数确实是均匀分布的

从内存内容中解释的
double
s的指数要么非常小,要么非常大。事实上,许多未使用的内存被清零,导致大量
0
值,这是有意义的。然而,正如我经常经历的跳出内存访问一样,在
1e+300附近也会出现很多值

我想解释一下这大量的超大
double
s

关于运行脚本的注意事项
如果您想自己尝试这个脚本,请注意您可能需要运行几次才能显示任何有趣的内容。从内存内容中读取的每个数字都可能是
0
,在这种情况下,它会告诉您是这样的。如果重复出现这种情况,请尝试降低
N
(使用的
双精度
s的数量)。

内存中可能有许多不同的内容,但数量惊人的内容会映射到非常大或非常小的浮点数、无穷大或NaN。在下文中,“FP”表示IEEE 754 64位二进制浮点

首先,因为他们已经讨论了这个问题的评论,考虑地址。一个64位地址通常具有所有指数位零(内存低端)或所有指数位高(内存高端,通常是堆栈地址)。如果所有的指数位都是高的,那么它就是一个无穷大或NaN,程序似乎忽略了它。如果所有指数位均为零,则为次正常数或零。次正态数均小于2.3E-308,以指数308计

现在考虑32位整数,另一种非常常见的数据形式。映射到有限FP的负32位2补整数为-1048577或更小。像-42或-1这样的数字映射到南边,被程序忽略。类似地,中等值正整数的所有指数位都为零,因此映射到次正态数,映射到直方图的大指数端。即使是小的正常数也相当于惊人的大整数。例如,1e-300的前导32位具有整数值 27618847


对于指针和整数,都存在对具有相同值的所有指数位的强烈偏向,要么全部为零,要么全部为一。所有1都是NaN或无穷大,不被程序计算在内。所有零都是低于正常值的,被算作非常大的指数。

所谓“随机”,实际上是指一致。均匀(随机)分布是指每个元素的发生概率相等的分布(或者,对于连续分布,每个区间的发生概率与区间大小成正比)。不同元素具有不同概率的分布仍然是随机的,只是不一致。内存布局倾向于将地址空间中的内容聚集在0、0x7fff…、0x8000…、0xffff…。因此,如果指针的值在0x7ff左右,则可以解释大的
double
值。@EricPostChil当这是预期的含义时,该问题特别使用“一致随机”一词。为什么内存布局会倾向于围绕这些值进行聚类?“如果……是真正随机的”,应该是“均匀分布的真正随机的”。“真正随机生成”应该是“真正随机生成且分布均匀”。内存布局围绕这些值聚集,因为很久以前人们坐在那里思考“我应该把东西放在哪里?”其中一些从0开始,然后将下一个东西放在1,然后是2,依此类推,或者放在4、8、12,或者任何他们需要的倍数。然后有人说,好的,我们已经把代码和一些数据放在那里了。嘿,我有个主意,让我们做一堆。我们应该把它放在哪里?由于已经使用了“底部”(0),可能它们从地址空间的顶部开始(当时可能是0xffff)向下工作。