关于 JavaScript Math.random() 和基本逻辑的问题

Posted

技术标签:

【中文标题】关于 JavaScript Math.random() 和基本逻辑的问题【英文标题】:Question about JavaScript Math.random() and basic logic 【发布时间】:2019-10-18 09:43:11 【问题描述】:

我写了一段简单的代码来比较随机数组的差异,发现了一些我不太明白的东西。

    我生成了 2 个用随机数填充的数组 将随机数之间的差异相加 打印出平均差

我原以为结果是接近 0.5 的随机数,但实际上是 0.3333。

为什么随机数数组归位在 0.3 而不是 0.5?

const result = document.getElementById('result');
const generateRandomNrArray = (nrNumbers) => 
	let i;
	let result = [];
	for (i = 0; i < nrNumbers; i++) 
		result.push(Math.random());
	
	return result;

const getArrayDiff = (arr1, arr2) => 
  var diff = 0;
  arr1.forEach(function (v1, index) 
      diff += Math.abs(v1 - arr2[index]);
  );
  return diff;

const run = (nr) => 
  const arr1 = generateRandomNrArray(nr);
  const arr2 = generateRandomNrArray(nr);
  const totalDiff = getArrayDiff(arr1, arr2); 
  
  result.innerhtml = "Average difference:" + (totalDiff / nr);
button font-size: 2em;
<div id="result"></div>
<button id="run" onclick="run(1500)">Click Me</button>

【问题讨论】:

Java 似乎也给出了结果。也许这将有助于解释这种行为? math.stackexchange.com/questions/637822/… 用 3 个数字再试一次,看看你的平均值是多少。您可能会看到模式 平均差可能趋于0。你说的是绝对差。 【参考方案1】:

这基本上归结为一个限制,这是有道理的。考虑 0 到 10 之间的数字组合,并计算您可以做出的各种差异。

例如,有一种组合,差值为 9 — (0, 9)。有5个相差5个:

[0, 5],  
[1, 6], 
[2, 7], 
[3, 8], 
[4, 9]

但相差1的组合有九种:

[1, 2], 
[2, 3], 

... 
[8, 9]

0 - 10 的计数是:

1: 9, 2: 8, 3: 7, 4: 6, 5: 5, 6: 4, 7: 3, 8: 2, 9: 1

有 45 种组合,这些组合的平均差异是 3.6666 而不是 5,因为较小的差异比较大的差异更多。

当您将粒度从 0 - 10 增加到 0 - 100 时,同样的模式成立。有 99 种组合导致差异 1,只有 50 种差异为 50,平均为 33.6666

当您在相反方向增加有效数字的数量时,在 0 和 1 之间进行越来越精细的划分,您会发现与极限接近 1/3 时相同的过程。与较大的差异相比,较小的差异会拉低平均差异。对于0-1,在 0.1 的间隔中,您会看到 9 的差异为 0.1,5 的差异为 0.5,在 0.01 时,99 的差异为 0.01,50 的差异为 0.5。随着区间接近 0,差异的平均值接近 1/3

【讨论】:

是的,使用固定的较大数字而不是细粒度的 0.xxxx 数字,问题变得更容易理解。 “...因为较小的差异比较大的差异更多” 这是一个很好的观点,但它提出了一些问题。为什么平均数不更小呢?例如 0.25。起初,我有一种直觉,由于某种神奇的数学原因,这个数字最终会成为 Math.PI。 @RainerPlumer 当你将区间随机分成两部分时,两部分的平均大小为1/2。如果随机选择两个数字,则将区间分成 3 个部分,每个部分的平均大小为1/3。那么这两个数字的平均差就是1/3 @Sulthan:您的评论比这里的每个答案都更清晰、更简洁。这本身就是一个很好的答案。【参考方案2】:

(事实上,您不是在看差异,而是看随机数之间的绝对差异。存在差异。(请原谅双关语))

如果您有两个独立的均匀分布随机变量X, Y ~ U[0,1],那么它们的绝对差|X-Y| 将遵循triangular distribution,期望为1/3。一切都是应有的。这个分布结果以及计算期望值是概率论中相当标准的作业问题。直觉直接跟随Mark's argument。

这里是绝对和非绝对差异的直方图。在左侧,您会看到较小的绝对差异有更多的质量,这拉低了期望值。

R 代码:

set.seed(1)
xx <- runif(1e5)
yy <- runif(1e5)
par(mfrow=c(1,2))
hist(abs(xx-yy),main="|X-Y|",col="grey",xlab="")
hist(xx-yy,main="X-Y",col="grey",xlab="")

(顺便说一句,如果您有概率/统计问题,我们的姊妹网站CrossValidated 是一个很好的资源。)

【讨论】:

【参考方案3】:

这里有一个几何参数来说明为什么结果会收敛到 1/3。

首先,让我们定义 f(x, y) = abs(x - y)。我们需要证明的是,对于X和Y是在[0, 1]中均匀分布的两个独立随机变量,E(X, Y) = 1/3。

如果我们将函数 f 在 3D 中可视化为正方形 [0, 1] x [0, 1] 上的高度场,则 f 下的体积由两个底为半单位正方形的四面体组成,其height 是一个单位高。

E(X, Y) 是 f 下的体积。根据金字塔体积公式,两个四面体中的每一个都有体积 a*h/3,其中 a 是它的底面积,h 是它的高度。这意味着每个四面体的体积为 1/2 * 1 * 1/3 = 1/6,因此 E(X, Y) = 2 * 1/6 = 1/3。

【讨论】:

【参考方案4】:

有一个简单自然的方式来看待这个:

如果你有一个区间,比如说&lt;0.0, 1.0&gt;,并且你从区间中随机选择一个数字,你实际上会将区间分成&lt;0.0, x&gt;&lt;x, 1.0&gt; 两部分。 每个部分的平均大小(在许多随机数上)将收敛到0.5

现在,如果您从区间中选择两个随机数,您会将区间分成三部分 &lt;0.0, x&gt;&lt;x, y&gt;&lt;y, 1.0&gt; (x &lt; y)。如果你在许多随机数上计算每个部分的平均大小,它将收敛到1/3

这两个数字的平均差就是零件的平均尺寸。

(原为评论)

【讨论】:

【参考方案5】:

离散变量法

以 N 个元素细分区间 [0;1](对应 k=1 到 N,X 将取值 k/N)。稍后我们会让 N 趋于 infty

对于给定的X_k(其中X 持有值k/N),计算平均距离,由下式给出

avgDistance(k) = sum_i=1^k (k-i)/N P(Y=i) + sum_i=k+1^n (i-k)/N P(Y=i)

第一项当 y

第一项求和 0 和 k 之间的距离,所以 1/N(k(k+1)/2),而第二项求和 1 和 N-k 之间的距离,所以 1/N(N-k)(N-k+1)。 此外,P(Y=i) = 1/N 对于所有 i(因为 Y 是均匀分布的)

因此

avgDistance(k) = 1/N^2 [ k(k+1)/2 + (N-k)(N-k+1)/2 ] = 1/(2N^2) [ 2k^2 + N^2 - 2kN + N ]

终于

avgDistance = sum_k=1^N avgDistance(k) P(X=k) = 1/N sum_k=1^N avgDistance(k) = 1/(2N^3) sum [ 2k^2 + N^2 - 2kN + N ]

想法是简化总和,如 aN^3 + ...项小于 N^3,因此当 N 趋于无穷大时,我们将简单地得到 aN^3/(2N^3) + 趋于 0

sum 2k^2 = 2(N(N+1)(2N+1))/6 ~ 4N^3/6
sum N^2 = N^3
sum -2kN = -2N(N(N+1)/2 ~= -N^3

因此a = 4/6avgDistance = 1/3

【讨论】:

以上是关于关于 JavaScript Math.random() 和基本逻辑的问题的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 随机

在javascript中math.random()的用法问题?有没有简单一点的说明?谢谢!

JavaScript中Math.random()方法产生的随机数包括0和1吗?

JavaScript - Math.floor(Math.random()) - 重新定位元素

Math.random() 的精度

javascript JS__Math.random()。JS