在 Javascript 中播种随机数生成器

Seeding the random number generator in Javascript

提问人:weepy 提问时间:2/7/2009 最后编辑:ashleedawgweepy 更新时间:9/26/2023 访问量:363596

问:

是否可以在 JavaScript 中播种随机数生成器 (Math.random)?

JavaScript 随机种子 播种

评论

4赞 simbo1905 5/16/2014
目前尚不清楚是否要播种它,以便在不同的测试运行中重复获得相同的结果,或者是否要为每个用户播种“独特的东西”,以便在使用之间获得更好的随机性。
5赞 Domenico De Felice 1/3/2015
不,很遗憾这是不可能的。jsrand 是我在需要可播种的 PRNG 时编写的一个小库。您还可以在谷歌上找到其他更复杂的库。
14赞 Alan 7/19/2018
增加一个问题:在没有播种方式的情况下提供 PRNG 怎么可能是一个好主意??这有什么充分的理由吗?
2赞 tidwall 9/16/2020
以下是此页面上一些生成器的可视化效果 observablehq.com/@tidwall/hello-randomness
7赞 codeulike 6/2/2021
@Alan我认为可能没有种子,因为底层算法取决于浏览器 - 如果 Math.random() 确实有种子,则不能保证种子在不同的浏览器中给出相同的结果。hackernoon.com/......

答:

244赞 PeterAllenWebb 2/7/2009 #1

不,不可能 播种 ,但是编写自己的生成器相当容易,或者更好的是,使用现有的生成器。Math.random()

查看:这个相关问题

另外,有关播种的更多信息,请参阅 David Bau 的博客。

52赞 Antti Kissaniemi 10/11/2013 #2

不,但这里有一个简单的伪随机生成器,这是我改编自维基百科的乘进位的实现(此后已被删除):

var m_w = 123456789;
var m_z = 987654321;
var mask = 0xffffffff;

// Takes any integer
function seed(i) {
    m_w = (123456789 + i) & mask;
    m_z = (987654321 - i) & mask;
}

// Returns number between 0 (inclusive) and 1.0 (exclusive),
// just like Math.random().
function random()
{
    m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask;
    m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask;
    var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
    result /= 4294967296;
    return result;
}

评论

3赞 Justin 1/1/2014
有没有人测试过这个函数的随机性?
3赞 Michael_Scharf 7/21/2014
这是具有相当长周期的乘进位 (MWC) 随机生成器。改编自维基百科 随机数生成器
0赞 Tomas Kubes 12/7/2014
当我将它与随机颜色生成器 (HSL) 一起使用时,它只生成绿色和青色。原始随机生成器生成所有颜色。所以,它不一样,或者不起作用。
0赞 ESL 9/18/2015
@Michael_Scharf 1)种子变化,而不是。2) 两者都基于它们以前的值而变化,因此它确实修改了结果。m_wm_zm_wm_z
0赞 Martin Omander 2/21/2017
当我使用此代码时,我没有得到分布良好的结果。无论种子如何,输出顺序都非常相似。这使得它对我的游戏没有帮助。
215赞 Antti Kissaniemi 10/11/2013 #3

注意:尽管(或者更确切地说,因为)简洁和明显的优雅,但就随机性而言,该算法绝不是高质量的算法。例如,寻找此答案中列出的那些以获得更好的结果。

(最初改编自评论中提出的一个聪明的想法,以回答另一个答案。

var seed = 1;
function random() {
    var x = Math.sin(seed++) * 10000;
    return x - Math.floor(x);
}

您可以设置为任何数字,只需避免零(或 Math.PI 的任意倍数)。seed

在我看来,这个解决方案的优雅之处在于没有任何“神奇”的数字(除了 10000,它代表了为避免奇怪模式而必须丢弃的最小数字数量 - 请参阅值为 10、100、1000 的结果)。 简洁也很好。

它比 Math.random() 慢一点(2 或 3 倍),但我相信它与用 JavaScript 编写的任何其他解决方案一样快。

评论

25赞 Nathan Breit 10/12/2013
有没有办法证明这个 RNG 生成的数字是均匀分布的?从实验上讲,它似乎:jsfiddle.net/bhrLT
11赞 A.M.K 5/2/2014
6,000,000 次操作/秒非常快,我不打算每次点击产生超过 ~3,000,000 次操作。开个玩笑,这太棒了。
72赞 spencer nelson 5/22/2014
-1,这根本不是一个统一的采样器 - 它非常偏向于 0 和 1(参见 jsfiddle.net/bhrLT/17,这可能需要一段时间来计算)。连续值是相关的 - 每 355 个值,甚至每 710 个值都是相关的。请使用更深思熟虑的东西!
59赞 Jason Goemaat 5/31/2014
问题不在于创建一个加密安全的随机数生成器,而在于在 javascript 中工作的东西,对快速演示等很有用。为此,我将采取一些快速而简单的东西,为一百万个随机数提供漂亮的分布。
26赞 Obiwahn 10/28/2015
小心。Math.sin() 可以在客户端和服务器上给出不同的结果。我使用Meteor(在客户端和服务器上使用javascript)。
33赞 user3581239 4/26/2014 #4

Antti Sykäri 的算法很好,很短。我最初做了一个变体,在你调用时替换了 JavaScript 的,但后来 Jason 评论说返回该函数会更好:Math.randomMath.seed(s)

Math.seed = function(s) {
    return function() {
        s = Math.sin(s) * 10000; return s - Math.floor(s);
    };
};

// usage:
var random1 = Math.seed(42);
var random2 = Math.seed(random1());
Math.random = Math.seed(random2());

这为您提供了 JavaScript 所没有的另一个功能:多个独立的随机生成器。如果您希望同时运行多个可重复的模拟,这一点尤其重要。

评论

4赞 Jason Goemaat 5/30/2014
如果你返回函数而不是设置,这将允许你有多个独立的生成器,对吧?Math.random
2赞 jocull 6/27/2016
如果这对您很重要,请务必查看上面关于随机性分布的评论:stackoverflow.com/questions/521295/......
0赞 SMUsamaShah 12/25/2016
由此产生的随机数如何重复?它每次都会不断给出新数字
0赞 WOUNDEDStevenJones 12/8/2017
每次你这样做时,它都会重置函数,所以如果你这样做,你会得到 ,那么 .如果你通过再次打电话来重置它,那么下次你打电话时你会再次得到,下次你会再次得到。Math.seed(42);var random = Math.seed(42); random(); random();0.70...0.38...var random = Math.seed(42);random()0.70...0.38...
6赞 Jack G 4/13/2018
请不要使用这个。请花点时间改用名为 的局部变量,而不是覆盖原生 javascript 函数。覆盖可能会导致 JIST 编译器取消优化所有代码。randomMath.random
7赞 user3158327 4/5/2015 #5

结合前面的一些答案,这是您正在寻找的可种子随机函数:

Math.seed = function(s) {
    var mask = 0xffffffff;
    var m_w  = (123456789 + s) & mask;
    var m_z  = (987654321 - s) & mask;

    return function() {
      m_z = (36969 * (m_z & 65535) + (m_z >>> 16)) & mask;
      m_w = (18000 * (m_w & 65535) + (m_w >>> 16)) & mask;

      var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
      result /= 4294967296;
      return result;
    }
}

var myRandomFunction = Math.seed(1234);
var randomNumber = myRandomFunction();

评论

4赞 undefined 4/19/2016
这在具有不同种子的序列开始时产生非常相似的结果。例如,返回 和 返回 。根据种子改变两者似乎会有所帮助。 生成具有不同种子的良好第一个值分布。Math.seed(0)()0.2322845458984375Math.seed(1)()0.23228873685002327m_wm_zvar m_w = 987654321 + s; var m_z = 123456789 - s;
2赞 bryc 2/23/2019
@undefined您描述的问题在上次编辑时已修复,但这是 MWC 实施中的一个错误。
0赞 ProfDFrancis 1/2/2020
截至 2020 年 1 月,现在运行良好。种子为 0,得到 0.7322976540308446。种子与1,0.16818441334180534,与2:0.6040864314418286,与3:0.03998844954185188。谢谢你们俩!
0赞 President James K. Polk 10/6/2022
我很好奇为什么它比更直接的更好.>>> 0& mask
6赞 Lajos Bodrogi 2/26/2017 #6

编写自己的伪随机生成器非常简单。

戴夫·斯科特斯(Dave Scotese)的建议是有用的,但正如其他人所指出的,它的分布并不完全均匀。

然而,这并不是因为罪的整数论证。这仅仅是因为罪的范围,而罪恰好是一个圆的一维投影。如果你取圆的角度,它将是均匀的。

所以而不是使用.sin(x)arg(exp(i * x)) / (2 * PI)

如果您不喜欢线性顺序,请将其与 xor 混合一点。实际因素也没那么重要。

要生成 n 个伪随机数,可以使用以下代码:

function psora(k, n) {
  var r = Math.PI * (k ^ n)
  return r - Math.floor(r)
}
n = 42; for(k = 0; k < n; k++) console.log(psora(k, n))

另请注意,当需要真实熵时,不能使用伪随机序列。

评论

0赞 bryc 3/6/2017
我不是专家,但连续的种子遵循恒定的模式。彩色像素为 >= 0.5。我猜它只是一遍又一遍地迭代半径?
3赞 Jason S 1/23/2023
“编写自己的伪随机生成器非常简单”——但编写正确的伪随机生成器却不是。
12赞 user2383235 3/5/2017 #7

请看Pierre L'Ecuyer的作品,可以追溯到1980年代末和1990年代初。还有其他的。如果您不是专家,自己创建一个(伪)随机数生成器是非常危险的,因为结果很可能不是统计随机的,或者周期很短。Pierre(和其他人)已经把一些很好的(伪)随机数生成器放在一起,这些生成器很容易实现。我使用他的一台LFSR发电机。

https://www.iro.umontreal.ca/~lecuyer/myftp/papers/handstat.pdf

评论

2赞 Nikolay Fominyh 3/5/2017
很好的答案,但与javascript无关:)
5赞 user2383235 3/6/2017
实现 L'Ecuyer 教授工作的代码是公开的 java 代码,大多数程序员可以很容易地翻译成 Javascript。
454赞 bryc 12/1/2017 #8

不,不可能播种。ECMAScript 规范在这个主题上故意含糊不清,没有提供播种的方法,甚至不要求浏览器使用相同的算法。因此,这样的功能必须由外部提供,值得庆幸的是,这并不难。Math.random()

我已经在纯 JavaScript 中实现了许多良好、简短和快速的伪随机数生成器 (PRNG) 函数。所有这些都可以播种并提供高质量的数字。这些不是出于安全目的 - 如果您需要可播种的 CSPRNG,请查看 ISAAC

首先,注意正确初始化您的 PRNG。为简单起见,下面的生成器没有内置的种子生成过程,但接受一个或多个 32 位数字作为 PRNG 的初始种子状态。相似或稀疏的种子(例如,1 和 2 的简单种子)具有低熵,并且可能导致相关性或其他随机性质量问题,有时会导致输出具有相似的属性(例如随机生成的级别相似)。为避免这种情况,最佳做法是使用分布均匀的高熵种子初始化 PRNG 和/或超过前 15 个左右的数字。

有很多方法可以做到这一点,但这里有两种方法。首先,哈希函数非常擅长从短字符串生成种子。即使两个字符串相似,一个好的哈希函数也会产生非常不同的结果,因此您不必在字符串上花费太多精力。下面是一个哈希函数示例:

function cyrb128(str) {
    let h1 = 1779033703, h2 = 3144134277,
        h3 = 1013904242, h4 = 2773480762;
    for (let i = 0, k; i < str.length; i++) {
        k = str.charCodeAt(i);
        h1 = h2 ^ Math.imul(h1 ^ k, 597399067);
        h2 = h3 ^ Math.imul(h2 ^ k, 2869860233);
        h3 = h4 ^ Math.imul(h3 ^ k, 951274213);
        h4 = h1 ^ Math.imul(h4 ^ k, 2716044179);
    }
    h1 = Math.imul(h3 ^ (h1 >>> 18), 597399067);
    h2 = Math.imul(h4 ^ (h2 >>> 22), 2869860233);
    h3 = Math.imul(h1 ^ (h3 >>> 17), 951274213);
    h4 = Math.imul(h2 ^ (h4 >>> 19), 2716044179);
    h1 ^= (h2 ^ h3 ^ h4), h2 ^= h1, h3 ^= h1, h4 ^= h1;
    return [h1>>>0, h2>>>0, h3>>>0, h4>>>0];
}

调用将从字符串生成一个 128 位哈希值,该值可用于为 PRNG 设定种子。以下是您可以使用它的方法:cyrb128

// Create cyrb128 state:
var seed = cyrb128("apples");
// Four 32-bit component hashes provide the seed for sfc32.
var rand = sfc32(seed[0], seed[1], seed[2], seed[3]);

// Only one 32-bit component hash is needed for mulberry32.
var rand = mulberry32(seed[0]);

// Obtain sequential random numbers like so:
rand();
rand();

注意:如果您想要一个稍微健壮的 128 位哈希,请考虑MurmurHash3_x86_128,它更全面,但适用于大型数组。

或者,只需选择一些虚拟数据来填充种子,并事先将生成器推进几次(12-20 次迭代)以彻底混合初始状态。这样做的好处是更简单,并且通常用于 PRNG 的参考实现,但它确实限制了初始状态的数量:

var seed = 1337 ^ 0xDEADBEEF; // 32-bit seed with optional XOR value
// Pad seed with Phi, Pi and E.
// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
var rand = sfc32(0x9E3779B9, 0x243F6A88, 0xB7E15162, seed);
for (var i = 0; i < 15; i++) rand();

注意:这些 PRNG 函数的输出产生一个正的 32 位数(0 到 232-1),然后将其转换为 0-1(包括 0,不包括 1)之间的浮点数,相当于 ,如果您想要特定范围的随机数,请阅读这篇关于 MDN 的文章。如果您只想要原始位,只需删除最终的除法操作即可。Math.random()

JavaScript 数字只能表示分辨率高达 53 位的整数。当使用按位运算时,这将减少到 32。其他语言的现代 PRNG 通常使用 64 位操作,这在移植到 JS 时需要填充码,这会大大降低性能。这里的算法只使用 32 位操作,因为它直接兼容 JS。

现在,继续讨论发电机。(我在这里维护带有参考资料和许可证信息的完整列表)


sfc32 (简单快速计数器)

sfc32PractRand 随机数测试套件的一部分(当然它通过了)。sfc32 具有 128 位状态,在 JS 中非常快。

function sfc32(a, b, c, d) {
    return function() {
      a |= 0; b |= 0; c |= 0; d |= 0; 
      var t = (a + b | 0) + d | 0;
      d = d + 1 | 0;
      a = b ^ b >>> 9;
      b = c + (c << 3) | 0;
      c = (c << 21 | c >>> 11);
      c = c + t | 0;
      return (t >>> 0) / 4294967296;
    }
}

您可能想知道 AND 是干什么用的。这些本质上是 32 位整数强制转换,用于性能优化。 在 JS 中基本上是浮点数,但在按位运算期间,它们切换到 32 位整数模式。JS 解释器处理此模式的速度更快,但任何乘法或加法都会导致它切换回浮点数,从而导致性能下降。| 0>>>= 0Number

桑树32

Mulberry32 是一个简单的生成器,具有 32 位状态,但速度极快且具有良好的随机性(作者表示它通过了 gjrand 测试套件的所有测试,并且具有完整的 232 周期,但我还没有验证)。

function mulberry32(a) {
    return function() {
      var t = a += 0x6D2B79F5;
      t = Math.imul(t ^ t >>> 15, t | 1);
      t ^= t + Math.imul(t ^ t >>> 7, t | 61);
      return ((t ^ t >>> 14) >>> 0) / 4294967296;
    }
}

如果您只需要一个简单但体面的 PRNG 并且不需要数十亿个随机数,我会推荐这个(请参阅生日问题)。

Xoshiro128**

截至 2018 年 5 月,xoshiro128** 是 Vigna & Blackman 的 Xorshift 家族的新成员(Vigna 教授还负责 Xorshift128+ 算法,该算法为大多数实现提供动力)。它是提供 128 位状态的最快生成器。Math.random

function xoshiro128ss(a, b, c, d) {
    return function() {
        var t = b << 9, r = b * 5; r = (r << 7 | r >>> 25) * 9;
        c ^= a; d ^= b;
        b ^= c; a ^= d; c ^= t;
        d = d << 11 | d >>> 21;
        return (r >>> 0) / 4294967296;
    }
}

作者声称它很好地通过了随机性测试(尽管有警告)。其他研究人员指出,它在TestU01中的一些测试中失败了(特别是LinearComp和BinaryRank)。在实践中,当使用浮点数时(例如在这些实现中),它不会导致问题,但如果依赖于原始最低阶位,则可能会导致问题。

JSF(Jenkins 的小快)

这是 Bob Jenkins (2007) 的 JSF 或“smallprng”,他还制作了 ISAACSpookyHash。它通过了 PractRand 测试,应该非常快,尽管不如 sfc32 快。

function jsf32(a, b, c, d) {
    return function() {
        a |= 0; b |= 0; c |= 0; d |= 0;
        var t = a - (b << 27 | b >>> 5) | 0;
        a = b ^ (c << 17 | c >>> 15);
        b = c + d | 0;
        c = d + t | 0;
        d = a + t | 0;
        return (d >>> 0) / 4294967296;
    }
}

评论

1赞 Lachmanski 6/11/2019
我相信你从“线性同余生成器表......”中引用的值。作者:Pierre L'ecuyer 可能会超过 Javascript 中的最大整数大小。最大种子 (2^32-1) * 741103597 ≈ 3e18,大于 JavaScript 的最大 int 大小 ≈ 9e15。我认为 Pierre 书中的以下值在原生限制内具有最大的周期:.seed = (seed * 185852 + 1) % 34359738337
2赞 bryc 6/11/2019
@Lachmanski真的,但这些都受 32 位(和 Park-Miller 31 位)的约束。使用允许它溢出,就像在 C 中对 32 位整数使用乘法时一样。你的建议是一个利用 JS 整数空间的 LCG,这绝对也是一个有趣的探索领域。:)Math.imul
2赞 user334639 8/8/2019
这太棒了!我可以将您的 sfc32 复制到 LGPL 程序中吗?
5赞 bryc 8/9/2019
当然,您可以随意将代码用于任何目的:)
5赞 bryc 12/5/2019
@blobber2不确定你的意思,但原始代码来自这里(与其他人):github.com/bryc/code/blob/master/jshash/PRNGs.md。或多或少是存储库中的要点:-)
2赞 Martin Omander 12/7/2017 #9

如今,许多需要 Javascript 中可播种随机数生成器的人都在使用 David Bau 的 seedrandom 模块

-12赞 Grimm Jack 4/10/2018 #10

对于介于 0 和 100 之间的数字。

Number.parseInt(Math.floor(Math.random() * 100))

评论

5赞 Jack G 4/13/2018
问题在于播种,这样每当用相同的种子播种时,它都会产生相同的连续随机数系列。可以说,这个问题与 的实际使用/演示无关。Math.randomMath.randomMath.random
-3赞 Tyler Hudson 4/13/2018 #11

我编写了一个返回种子随机数的函数,它使用 Math.sin 获得一个长随机数,并使用种子从中挑选数字。

用:

seedRandom("k9]:2@", 15)

它将返回您的种子号码 第一个参数是任意字符串值;你的种子。 第二个参数是将返回的位数。

     function seedRandom(inputSeed, lengthOfNumber){

           var output = "";
           var seed = inputSeed.toString();
           var newSeed = 0;
           var characterArray = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','y','x','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','U','R','S','T','U','V','W','X','Y','Z','!','@','#','$','%','^','&','*','(',')',' ','[','{',']','}','|',';',':',"'",',','<','.','>','/','?','`','~','-','_','=','+'];
           var longNum = "";
           var counter = 0;
           var accumulator = 0;

           for(var i = 0; i < seed.length; i++){
                var a = seed.length - (i+1);
                for(var x = 0; x < characterArray.length; x++){
                     var tempX = x.toString();
                     var lastDigit = tempX.charAt(tempX.length-1);
                     var xOutput = parseInt(lastDigit);
                     addToSeed(characterArray[x], xOutput, a, i); 
                }                  
           }

                function addToSeed(character, value, a, i){
                     if(seed.charAt(i) === character){newSeed = newSeed + value * Math.pow(10, a)}
                }
                newSeed = newSeed.toString();

                var copy = newSeed;
           for(var i=0; i<lengthOfNumber*9; i++){
                newSeed = newSeed + copy;
                var x = Math.sin(20982+(i)) * 10000;
                var y = Math.floor((x - Math.floor(x))*10);
                longNum = longNum + y.toString()
           }

           for(var i=0; i<lengthOfNumber; i++){
                output = output + longNum.charAt(accumulator);
                counter++;
                accumulator = accumulator + parseInt(newSeed.charAt(counter));
           }
           return(output)
      }

评论

1赞 Gabriel 6/26/2018
由此产生的数字序列并不能真正近似于随机数序列的属性。例如,用它生成 15 个数字,生成的字符串几乎总是以 7 开头,几乎任何键。
-4赞 Carlos Oliveira 4/30/2018 #12

固定种子的简单方法:

function fixedrandom(p){
    const seed = 43758.5453123;
    return (Math.abs(Math.sin(p)) * seed)%1;
}
3赞 Ulf Aslak 4/10/2019 #13

Math.random不,但 RAN解决了这个问题。它几乎具有您能想象到的所有分布,并支持种子随机数生成。例:

ran.core.seed(0)
myDist = new ran.Dist.Uniform(0, 1)
samples = myDist.sample(1000)
1赞 Kirill Groshkov 1/19/2021 #14

这是 Jenkins 哈希的采用版本,借用自这里

export function createDeterministicRandom(): () => number {
  let seed = 0x2F6E2B1;
  return function() {
    // Robert Jenkins’ 32 bit integer hash function
    seed = ((seed + 0x7ED55D16) + (seed << 12))  & 0xFFFFFFFF;
    seed = ((seed ^ 0xC761C23C) ^ (seed >>> 19)) & 0xFFFFFFFF;
    seed = ((seed + 0x165667B1) + (seed << 5))   & 0xFFFFFFFF;
    seed = ((seed + 0xD3A2646C) ^ (seed << 9))   & 0xFFFFFFFF;
    seed = ((seed + 0xFD7046C5) + (seed << 3))   & 0xFFFFFFFF;
    seed = ((seed ^ 0xB55A4F09) ^ (seed >>> 16)) & 0xFFFFFFFF;
    return (seed & 0xFFFFFFF) / 0x10000000;
  };
}

你可以像这样使用它:

const deterministicRandom = createDeterministicRandom()
deterministicRandom()
// => 0.9872818551957607

deterministicRandom()
// => 0.34880331158638
-6赞 manasGain 1/29/2021 #15

在PHP中,有一个函数可以为特定的种子生成固定的随机值。 但是,在 JS 中,没有这样的内置函数。srand(seed)

但是,我们可以编写简单而简短的函数。

1:选择一些种子(固定编号)。

Number 应为正整数且大于 1,在步骤 2 中进一步说明。
var seed = 100;

2:在 Seed 上执行 Math.sin() 函数,它将给出该数字的 sin 值。将此值存储在变量 x 中。

var x; 
x = Math.sin(seed); // Will Return Fractional Value between -1 & 1 (ex. 0.4059..)

sin() 方法返回一个介于 -1 和 1 之间的小数值。
而且我们不需要负值,因此,在第一步中选择大于 1 的数字。

3:返回值是介于 -1 和 1 之间的小数值。
因此,将此值与 10 进行复数,使其大于 1。

x = x * 10; // 10 for Single Digit Number

4:将值乘以 10 以获得其他数字

x = x * 10; // Will Give value between 10 and 99 OR
x = x * 100; // Will Give value between 100 and 999

根据数字要求相乘。

结果将以十进制表示。

5:通过数学的 Round (Math.round()) 方法删除小数点后的值。

x = Math.round(x); // This will give Integer Value.

6:通过 Math.abs 方法将负值转换为正值(如果有)

x = Math.abs(x); // Convert Negative Values into Positive(if any)

解释结束。

最终代码

var seed = 111; // Any Number greater than 1
var digit = 10 // 1 => single digit, 10 => 2 Digits, 100 => 3 Digits and so. (Multiple of 10) 

var x; // Initialize the Value to store the result
x = Math.sin(seed); // Perform Mathematical Sin Method on Seed.
x = x * 10; // Convert that number into integer
x = x * digit; // Number of Digits to be included
x = Math.round(x); // Remove Decimals
x = Math.abs(x); // Convert Negative Number into Positive

干净和优化的功能代码

function random_seed(seed, digit = 1) {
    var x = Math.abs(Math.round(Math.sin(seed++) * 10 * digit));
    return x;
}

然后使用

any_number is must 且 should 大于 1 调用此函数。
number_of_digits 是可选参数,如果未传递任何参数,则返回 1 位数字。
random_seed(any_number, number_of_digits)

random_seed(555); // 1 Digit
random_seed(234, 1); // 1 Digit
random_seed(7895656, 1000); // 4 Digit

评论

2赞 penduDev 1/30/2021
这个函数是有偏差的,因为 abs(Math.sin(random_number)) 本身就是一个偏向于 sin 函数斜率为零的点附近的函数。以下是可以在 js 控制台中运行进行实验的代码:(pastebin.com/kJyHaQYY)
0赞 penduDev 1/30/2021 #16

这里的大多数答案都会产生有偏见的结果。所以这里有一个基于 github 的 seedrandom 库的测试函数:

!function(f,a,c){var s,l=256,p="random",d=c.pow(l,6),g=c.pow(2,52),y=2*g,h=l-1;function n(n,t,r){function e(){for(var n=u.g(6),t=d,r=0;n<g;)n=(n+r)*l,t*=l,r=u.g(1);for(;y<=n;)n/=2,t/=2,r>>>=1;return(n+r)/t}var o=[],i=j(function n(t,r){var e,o=[],i=typeof t;if(r&&"object"==i)for(e in t)try{o.push(n(t[e],r-1))}catch(n){}return o.length?o:"string"==i?t:t+"\0"}((t=1==t?{entropy:!0}:t||{}).entropy?[n,S(a)]:null==n?function(){try{var n;return s&&(n=s.randomBytes)?n=n(l):(n=new Uint8Array(l),(f.crypto||f.msCrypto).getRandomValues(n)),S(n)}catch(n){var t=f.navigator,r=t&&t.plugins;return[+new Date,f,r,f.screen,S(a)]}}():n,3),o),u=new m(o);return e.int32=function(){return 0|u.g(4)},e.quick=function(){return u.g(4)/4294967296},e.double=e,j(S(u.S),a),(t.pass||r||function(n,t,r,e){return e&&(e.S&&v(e,u),n.state=function(){return v(u,{})}),r?(c[p]=n,t):n})(e,i,"global"in t?t.global:this==c,t.state)}function m(n){var t,r=n.length,u=this,e=0,o=u.i=u.j=0,i=u.S=[];for(r||(n=[r++]);e<l;)i[e]=e++;for(e=0;e<l;e++)i[e]=i[o=h&o+n[e%r]+(t=i[e])],i[o]=t;(u.g=function(n){for(var t,r=0,e=u.i,o=u.j,i=u.S;n--;)t=i[e=h&e+1],r=r*l+i[h&(i[e]=i[o=h&o+t])+(i[o]=t)];return u.i=e,u.j=o,r})(l)}function v(n,t){return t.i=n.i,t.j=n.j,t.S=n.S.slice(),t}function j(n,t){for(var r,e=n+"",o=0;o<e.length;)t[h&o]=h&(r^=19*t[h&o])+e.charCodeAt(o++);return S(t)}function S(n){return String.fromCharCode.apply(0,n)}if(j(c.random(),a),"object"==typeof module&&module.exports){module.exports=n;try{s=require("crypto")}catch(n){}}else"function"==typeof define&&define.amd?define(function(){return n}):c["seed"+p]=n}("undefined"!=typeof self?self:this,[],Math);

function randIntWithSeed(seed, max=1) {
  /* returns a random number between [0,max] including zero and max
  seed can be either string or integer */
  return Math.round(new Math.seedrandom('seed' + seed)()) * max
}

测试此代码的真实随机性:https://es6console.com/kkjkgur2/

7赞 ccxvii 6/23/2022 #17

不可能为内置的 Math.random 函数提供种子,但可以在 Javascript 中用很少的代码实现高质量的 RNG。

Javascript 数字是 64 位浮点精度,可以表示所有小于 2^53 的正整数。这给我们的算术设置了硬性限制,但在这些限制范围内,您仍然可以为高质量的 Lehmer / LCG 随机数生成器选择参数。

function RNG(seed) {
    var m = 2**35 - 31
    var a = 185852
    var s = seed % m
    return function () {
        return (s = s * a % m) / m
    }
}

Math.random = RNG(Date.now())

如果你想要更高质量的随机数,但代价是速度要慢 ~10 倍,你可以使用 BigInt 进行算术运算,并选择 m 刚好可以放入双精度值的参数。

function RNG(seed) {
    var m_as_number = 2**53 - 111
    var m = 2n**53n - 111n
    var a = 5667072534355537n
    var s = BigInt(seed) % m
    return function () {
        return Number(s = s * a % m) / m_as_number
    }
}

请参阅 Pierre l'Ecuyer 的这篇论文,了解上述实现中使用的参数: https://www.ams.org/journals/mcom/1999-68-225/S0025-5718-99-00996-5/S0025-5718-99-00996-5.pdf

无论你做什么,都要避免使用Math.sin的所有其他答案!

评论

0赞 Adam Gawne-Cain 10/14/2023
为什么 m=2 * * 35 ?要使用全范围的整数值,它应该是 m=Math.floor(2 * * 53 / a)?
0赞 ccxvii 10/15/2023
将 m 和 a 的值一起选择以生成一个看起来随机的序列。如果你选择不好的值,你最终可能会遇到 RANDU 的情况。请参阅答案中引用的论文和 Park & Miller 的 ACM 文章“随机数生成器:好的生成器很难找到”(可在 scihub 上找到)。
1赞 RaySun 7/29/2022 #18

不,就像他们说的,不可能播种 Math.random() 但是您可以安装外部软件包来为此做好准备。我使用了这些软件包,可以使用这些命令进行安装

npm i random-seed

该示例是从包文档中获取的。

var seed = 'Hello World',
rand1 = require('random-seed').create(seed),
rand2 = require('random-seed').create(seed);
console.log(rand1(100), rand2(100));

点击链接获取文档 https://www.npmjs.com/package/random-seed

1赞 Eric Van Bezooijen 10/24/2022 #19

这里有很多很好的答案,但我有一个类似的问题,即我希望 Java 的随机数生成器和我最终在 JavaScript 中使用的任何东西之间的可移植性。

我找到了java-random包

假设种子相同,这两段代码具有相同的输出:

爪哇岛:

Random randomGenerator = new Random(seed);
int randomInt;
for (int i=0; i<10; i++) {
    randomInt = randomGenerator.nextInt(50);
    System.out.println(randomInt);
}

JavaScript的:

let Random = require('java-random');
let rng = new Random(seed);
for (let i=0; i<10; i++) {
    let val = rng.nextInt(50);
    console.log(val);
}
1赞 Denis TRUFFAUT 1/12/2023 #20

SIN(id + seed) 是一个非常有趣的 RANDOM 函数的替代品,它不能像 SQLite 那样被植入:

https://stackoverflow.com/a/75089040/7776828

1赞 Boddle 2/25/2023 #21

按照 bryc 的建议去做......但在使用他的 cyrb128 哈希函数进行初始化之前,请注意 return 语句丢弃了 32 位熵。Exclusive-or 四个值一起 = 0。您可能应该将第一个元素 (h2^h3^h4) 设>>> 0。

评论

0赞 bryc 7/27/2023
这是一个错误。固定。尽管您应该发表评论而不是单独回答。;)
1赞 Boddle 7/28/2023
感谢您的认可,bryc,我同意,但没有足够的声誉来发表评论