28

我有各种依赖 javascript 随机数的资源。但是,由于我生成随机数的方式,我已经看到了很多随机不是那么随机的问题。

是否有任何 javascript 资源可供我生成真实的或更好的随机数?

我知道我可以与 Random.org 交互,但我还有哪些其他选择?

我正在使用:

function rand( lowest, highest){
    var adjustedHigh = (highest - lowest) + 1;       
    return Math.floor(Math.random()*adjustedHigh) + parseFloat(lowest);
}
4

8 回答 8

24

假设您不只是看到不存在的模式,请尝试 Mersenee Twister(此处为 Wikipedia 文章)。在 github 上有各种类似的实现。

类似的问题:

可播种的 JavaScript 随机数生成器

如果你想要更接近真正随机的东西,那么考虑使用random.org API来获得真正的随机数,尽管我建议只使用它来播种,而不是每个数字,因为你需要遵守它们的使用限制。

于 2012-10-01T12:57:15.870 回答
21

调整数字,使它们“看起来随机”

我同意 Phil H 的观点,即人类非常善于发现模式,以至于他们经常认为即使在“完全随机”的数字序列中也能看到模式(聚类错觉、apophenia、赌徒谬误等)。

真正随机位置的图通常有很多“巧合”非常靠近的团块和点,这看起来很可疑。

艺术家经常采用完全随机生成的图案并“轻推”它们以使它们看起来“更随机”,即使仔细轻推实际上会使图案不那么随机(a)(b)(c)(d)等。

或者,低差异序列有时比真正的随机序列“看起来更好”,并且生成速度要快得多。

快速随机数生成器

从“极快”到“相对慢”,从“即使是人类也很容易看到模式”到“无人协助的人不可能看到任何模式”到“密码安全”,整个范围内都有许多“随机数生成器”并且,在植入足够量的熵之后,据我们所知,对于任何使用少于人类一个月产生的能量的攻击者来说,它与随机无异。”

仍然提供出色输出的非加密强度随机数生成器(不太可能没有辅助的人类可以看到任何模式)包括Mersenne twistermultiply-with-carryLagged Fibonacci generatorWell equidistributed long-period linearXorshift等。

适用于某些浏览器的加密随机数技术

我听说Cryptocat和其他 JavaScript 应用程序使用方便的window.crypto.getRandomValues()or window.msCrypto.getRandomValues()orSubtleCrypto.generateKey()函数来生成加密随机数。不幸的是,该功能在 IE 11 及更低版本中不可用。

由于网络浏览器一直使用随机数(对于它们获取的每个“https://”页面),这些函数(如果可用)很可能比大多数用 JavaScript 编写的随机数生成器运行得更快——甚至是非加密的算法。

兼容古代和现代浏览器的密码随机数技术

在 JavaScript 中生成真正随机数的一种方法是捕获鼠标事件并将它们添加到熵池中,跟踪添加的熵的一些(希望是保守的)估计。一旦池“满”(估计表明至少添加了 128 位熵),使用一些密码安全的随机数生成器从池中生成随机数 - 通常使用单向哈希,以便序列几千个输出数不足以推断熵池的状态并因此预测下一个输出数。

一种实现方式:http: //lightsecond.com/passphrase.html

进一步阅读

于 2014-02-11T03:16:58.530 回答
4

在寻找 Math.random 的替代方案时,我偶然发现了这个问题。

虽然这些是有效的答案,但对我有用的解决方案只是使用 Math.random 两次。
并在浮点数的小数上使用模数。
基本上是为了增加随机性。

也许它可能对一些被谷歌引导到这个问题的人有用。

这是一个包含该功能的片段,并且运行了一百万次。

function rand(min, max){
    return (Math.floor(Math.pow(10,14)*Math.random()*Math.random())%(max-min+1))+min;
}

// testing rand
function rollRands(min, max, rolls) {
    let roll = 0, n = 0;
    let counts = {};
    
    for(let i = min; i <= max; i++){
        counts[i]=0
    }

    while (roll < rolls){
        roll++;
        counts[rand(min,max)]++;
    }
    return counts;
}
  
console.log(rollRands(36, 42, 1000000));

于 2020-01-14T14:25:31.227 回答
3

Rando.js在密码学上是安全的。它基本上window.crypto.getRandomValues()用作window.msCrypto.getRandomValues()故障保护和Math.random()最后的故障保护,但它更容易实现和使用。这是一个基本的密码安全随机 [0, 1) 数:

console.log(rando());
<script src="https://randojs.com/2.0.0.js"></script>

好,易于。如果这就是你想要的,你就可以走了。如果你想让它为你做更多的事情,它也能做到这一切:

console.log(rando(5));                      //an integer between 0 and 5 (could be 0 or 5));  
console.log(rando(5, 10));                  //a random integer between 5 and 10 (could be 5 or 10));  
console.log(rando(5, "float"));             //a floating-point number between 0 and 5 (could be exactly 0, but never exactly 5));  
console.log(rando(5, 10, "float"));         //a floating-point number between 5 and 10 (could be exactly 5, but never exactly 10));  
console.log(rando(true, false));            //either true or false  
console.log(rando(["a", "b"]));             //{index:..., value:...} object representing a value of the provided array OR false if array is empty  
console.log(rando({a: 1, b: 2}));           //{key:..., value:...} object representing a property of the provided object OR false if object has no properties  
console.log(rando("Gee willikers!"));       //a character from the provided string OR false if the string is empty. Reoccurring characters will naturally form a more likely return value  
console.log(rando(null));                   //ANY invalid arguments return false  

//Prevent repetitions by grabbing a sequence and looping through it
console.log(randoSequence(5));              //an array of integers from 0 through 5 in random order  
console.log(randoSequence(5, 10));          //an array of integers from 5 through 10 in random order  
console.log(randoSequence(["a", "b"]));     //an array of {index:..., value:...} objects representing the values of the provided array in random order  
console.log(randoSequence({a: 1, b: 2}));   //an array of {key:..., value:...} objects representing the properties of the provided object in random order  
console.log(randoSequence("Good gravy!"));  //an array of the characters of the provided string in random order  
console.log(randoSequence(null));           //ANY invalid arguments return false
<script src="https://randojs.com/2.0.0.js"></script>

它也支持使用 jQuery 元素,但我没有在这个演示中使用它,所以我不必在 jQuery 中获取源代码。如果您需要,只需在GitHub网站上查看。

于 2020-07-18T19:18:14.860 回答
2

更好的是,您可以使用量子密码学来生成非常难以预测的随机性。您可以使用ANU Quantum Random Numbers API来获得一些随机性,这些随机性可以强制转换为类似的数字输出Math.random

于 2020-07-18T06:48:31.417 回答
2

这里似乎在两件非常不同的事情之间存在轻微的混淆:

  • 随机数;
  • 伪随机数。

向那些已经知道这一点的人道歉,但这两者是天壤之别。伪随机数看起来是随机的,甚至可以通过复杂的随机性测试,但它们是确定性的。因此,它们对密码学毫无用处,并且可能存在需要真正随机性的其他缺陷。

真正的随机性是不确定的,因此是不可预测的。这里的一个关键概念是熵,或包含的非冗余信息量。获得真正随机数据的方法数量有限。“好”的来源是:

  1. 放射性衰变——通常很难做到;
  2. 背景无线电噪声——与普遍认为的相反,这主要与大爆炸的背景微波辐射无关,而是更狭隘;
  3. 电子通过反向偏置齐纳二极管移动的噪声:实际上非常有用且在实践中易于实现,电路简单。

其他“随机性来源”,如鼠标移动和计算机磁盘计时的内部变化等,经常被利用,但可能不够完美。一般来说,我发现在 Linux 系统上访问熵池比在 Windows 下更容易,但这可能只是个人偏见。

如果您只想要随机出现的数字,那么可以,使用 Mersenne twister 是一个可行的选择。它疯狂地跳来跳去。如果您正在生成随机数以用作例如版本 4 UUID,那么您需要更加小心。如果它不存在,您不能简单地“添加熵”,即使通过应用确定性加密函数也是如此。

如果您打算将随机性用于密码学,您还应该密切注意随机性来源可能受到损害的多种方式。例如,如果您使用基于 Internet 的“随机性来源”,谁能利用它?

于 2020-10-10T01:30:13.190 回答
1

您可以通过异步请求一些数据来生成一个随机数池,因为 performance.now() 可以为您提供高达微秒的时间精度。然后将响应时间用作随机算法中的盐,

var randomNumbers = [];
for(var i = 0; i < 10; i++) {
  setTimeout(function () {
    var timeStart = performance.now();
    xhttp = new XMLHttpRequest();
    xhttp.open('GET', 'https://cdn.polyfill.io/v2/polyfill.min.js?rand=' + Math.random(), true);
    xhttp.onload = function () {
      var timeEnd = performance.now() - timeStart;
      var rNumber = parseInt(timeEnd.toString().replace('.', ''));
      randomNumbers.push(rNumber)
    };
    xhttp.send();
  }, i * 10);
}

影响这个时间的因素有很多:

  • 浏览器速度
  • 走一条路
  • 服务器响应时间
  • 回程

以这种方式生成数百万个数字是不好的,但很少。也许连接一些结果以获得一个好的、长的随机数。

于 2016-09-07T16:28:37.870 回答
-7

我制作了一个 JavaScript 库,它使用余弦和正弦函数使用 Date.now() 和 new Date().getTime() 生成随机数。对于每个随机数,我都会测试该数字是否已被使用。如果有,我重复这个过程,直到我得到一个新号码。如果我得到一个新号码,我将这个号码添加到已用列表中,然后返回该值。在同一个库中,我还添加了一个随机性测试器,它循环通过一个随机数生成器并寻找模式。这种方式很好,因为它可以快速加载数字(我用 console.time 计时),而无需不必要地联系其他页面。

你可以在这里找到这个库:punbb.atspace.cc/scripts/libraries/random.js

于 2017-07-31T22:43:40.390 回答