调用 Math.random() 的函数是纯的吗?

2022-08-30 05:23:04

以下函数是纯函数吗?

function test(min,max) {
   return  Math.random() * (max - min) + min;
}

我的理解是,纯函数遵循以下条件:

  1. 它返回从参数计算的值
  2. 除了计算返回值之外,它不执行任何其他工作

如果这个定义是正确的,我的函数是纯函数吗?还是我对定义纯函数的理解不正确?


答案 1

不,它不是。给定相同的输入,此函数将返回不同的值。然后,您无法构建映射输入和输出的“表”。

来自纯函数的维基百科文章:

该函数始终在给定相同参数值的情况下计算相同的结果值。函数结果值不能依赖于在程序执行过程中或在程序的不同执行之间可能更改的任何隐藏信息或状态,也不能依赖于来自 I/O 设备的任何外部输入。

另外,另一件事是纯函数可以用表示输入和输出映射的表替换,如此线程中所述。

如果要重写此函数并将其更改为纯函数,则还应将随机值作为参数传递

function test(random, min, max) {
   return random * (max - min) + min;
}

然后以这种方式调用它(例如,将 2 和 5 作为最小值和最大值):

test( Math.random(), 2, 5)

答案 2

你的问题的简单答案是Math.random()违反了规则#2。

这里的许多其他答案都指出,存在意味着这个函数不是纯的。但我认为值得一提的是,为什么会污染使用它的函数。Math.random()Math.random()

像所有伪随机数生成器一样,以“种子”值开头。然后,它将该值用作一系列低级位操作或其他操作的起点,这些操作会导致不可预知(但不是真正随机的)输出。Math.random()

在JavaScript中,所涉及的过程依赖于实现,并且与许多其他语言不同,JavaScript不提供选择种子的方法

该实现选择随机数生成算法的初始种子;用户无法选择或重置它。

这就是为什么这个函数不是纯粹的:JavaScript本质上是使用一个你无法控制的隐式函数参数。它从计算并存储在其他位置的数据中读取该参数,因此违反了定义中的规则 #2。

如果要使此函数成为纯函数,可以使用此处描述的替代随机数生成器之一。调用该生成器 。它采用一个参数(种子)并返回一个“随机”数字。当然,这个数字根本不是随机的。它是由种子唯一决定的。这就是为什么这是一个纯函数。的输出只是“随机”的,因为根据输入预测输出是困难的。seedable_randomseedable_random

此函数的纯版本需要采用个参数:

function test(min, max, seed) {
   return  seedable_random(seed) * (max - min) + min;
}

对于任何给定的三重参数,这将始终返回相同的结果。(min, max, seed)

请注意,如果您希望 的输出真正随机,则需要找到一种方法来随机化种子!无论你使用什么策略,都不可避免地是非纯粹的,因为它需要你从函数之外的来源收集信息。正如mtraceurjpmc26提醒我的那样,这包括所有物理方法:硬件随机数发生器带镜头盖的网络摄像头大气噪声收集器 - 甚至熔岩灯。所有这些都涉及使用在函数外部计算和存储的数据。seedable_random