还记得先前提到 Math.random
并非是纯函式吗,因为每次给定相同的输入都会是不同的输出回传回来,那有什麽办法可以让它是回传乱数,又可以是纯函数呢? 没错,PRNG乱数生成器!在用 State Monad 实作前,先来用一般的方式实作看看!
简单来说 PRNG 的概念就是先给定一个数值,称为 seed, 将其放入 generator
中,取得一个 nextSeed 之後,又可以将 nextSeed 放入 generator
产生新的乱数。
const generator = (seed) => (seed * 1103515245 + 12345) & 0x7fffffff;
const seed = 1;
const randomNumber1 = generator(seed); // 1103527590
const randomNumber2 = generator(randomNumber1) // 377401600
而我们写的 generator 能确保每次给定相同输入就会有相同输出!
有这个能干嘛呢? 我们可以用它来实作一个给定特定范围,就会随机回传特定范围数值的函式
const value = (seed) => (seed >>> 16) / 0x7fff;
const normalize = (min, max) => (x) => Math.floor(x * (max - min)) + min;
const randomInRange = (min, max) => (seed) => {
const nextSeed = generator(seed);
const random = R.compose(normalize(min, max), value)(nextSeed);
return [nextSeed, random];
};
这样就可以随机产生特定范围的乱数,而由於我们还需要用下一个 seed 的值去造下一组数,所以必须将下一个 seed 也一并传出,
const seed = 1;
const [n1, r1] = randomInRange(0, 10)(seed) // 5
const [n2, r2] = randomInRange(0, 10)(n1) // 1
既然都可以乱数产生特定范围的数值了,也可以用此一算法,去随机取出阵列中某一个项目
const name = ["jing", "jing*5", "jing-tech"];
const randomName = (from) => (seed) => {
const [n1, r1] = randomInRange(seed, 0, from.length)
return [n1, name[r1]];
}
const [n1, name] = randomName(name)(1) // '1103527590, jing*5'
大致介绍完 PRNG 的概念了,可以反思一下如果现在要从某种阵列(资料)内抽取很多组不同的值呢? 又或是想要一次用同一组乱数不同阵列(资料)取值呢? 这样是不是会让程序复杂度上升呢?
没错,本章就先介绍到这里,下一章带大家来看 State Monad 是如何处理这种问题的!
感谢大家阅读!
<<: Day 29 Realm的练习-使用者注册系统(3/3)
为了方便之後丢多点图进行测试,我将图片放进了 img 资料夹,并使用 glob 获得图片列表。 同时...
写完第26天之後我思考了很久(大概一天),因为 Google maps 的功能也介绍的差不多了,但是...
最近都在全台跑面试 都没时间继续写.. 刚好面试某金控 面试官出了个回家作业给我 就花了一个下午把它...
专业必备技能:应用程序相关 https://wolkesau.medium.com/专业必备技能-应...
In my career path, there is one type of job that I...