[Functional Programming] Build a Linear congruential generator

本文介绍如何使用JavaScript创建一个线性同余随机数生成器,该生成器能产生可重复的随机数序列,适用于游戏等需要固定随机性的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

What we are going to do in this post, is to build a random number generator. As you might know that Javascript provides Math.random(), but the problem for Math.random() is you cannot control it, what we actully want is a number generator which can provide the same sequence of random numbers. Imaging we have a game, everytime we start the game it will genarte 

[5,7,9,8,1,3....]

Second times, it runs the game, it produce the same output: [5,7,9,8,1,3....]. This kind of number generator is called: Linear congruential generator 

 

We are going to use 'crocks/State' to coding it:

const log = require('./lib/log');

const State = require('crocks/State');
const B = require('crocks/combinators/composeB');
const K = require('crocks/combinators/constant');
const prop = require('crocks/Maybe/prop');
const option = require('crocks/pointfree/option');
const {modify, get} = State;
const assign = require('crocks/helpers/assign');

// pluckSeed :: Integer -> Object -> Integer
const pluckSeed =
    def => B(option(def), prop('seed'))

// rando : Integer -> State Object Float
const rando = x => {
    const seed = (1103515245 * x + 12345) & 0x7fffffff
    const value = (seed >>> 16) / 0x7fff;

    return modify(assign({seed})) // update the seed Pair(_, seed)
        .map(K(value)); // update the value Pair(value, seed)
}

// pullRandom :: Integer -> State Object Float
const pullRandom =
    defSeed => get(pluckSeed(defSeed)).chain(rando);

// limitIndx :: Integer -> Float -> Integer
const limitIndx = len => x => (x * len) | 0;

const seed = 76;
log(
    State.of(seed)
    .chain(pullRandom) // 'Pair( 0.13864558854945525, { seed: 297746555 } )'
    .map(limitIndx(52)) // 'Pair( 7, { seed: 297746555 } )'
    .runWith({seed: 10})
);

 

Let's explain some operator a little bit:

const B = require('crocks/combinators/composeB');

'composeB', the same as 'compose' read from right to left, the only difference is it only accepts two functions! no more no less.

// pluckSeed :: Integer -> Object -> Integer
const pluckSeed =
    def => B(option(def), prop('seed'))

'pluckSeed', we use 'prop' from 'Maybe', to get value from Maybe, we need to use 'option', if Maybe returns Nothing, then we use the default value from 'option(def)'.

 

const State = require('crocks/State');
const {modify, get} = State;

// rando : Integer -> State Object Float
const rando = x => {
    const seed = (1103515245 * x + 12345) & 0x7fffffff
    const value = (seed >>> 16) / 0x7fff;

    return modify(assign({seed})) // update the seed Pair(_, seed)
        .map(K(value)); // update the value Pair(value, seed)
}

'modify' it a constructor' method for 'State' moand, the State monad is constructed by Pair moand:

State(Pair(a, s))

On the left side, 'a' is the new state which come from 's' after mapping to some function. 's' is the origianl state.

When you call 'modify', it is actually modifying the right side 's':

modify(assign({seed})) // update the seed Pair(_, seed)

When you call .map(fn), it is change the value on the left side of Pair:

    return modify(assign({seed})) // update the seed Pair(_, seed)
        .map(constant(value)); // update the value Pair(value, seed)

 

转载于:https://www.cnblogs.com/Answer1215/p/10544101.html

要在C语言中实现Permuted Congruential Generator(PCG)算法,可以使用PCG官方提供的C语言参考实现。以下是一个简单的示例代码: ```c #include <stdint.h> typedef struct { uint64_t state; uint64_t inc; } pcg32_random_t; void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq) { rng->state = 0U; rng->inc = (initseq << 1u) | 1u; pcg32_random_r(rng); rng->state += initstate; pcg32_random_r(rng); } uint32_t pcg32_random_r(pcg32_random_t* rng) { uint64_t oldstate = rng->state; rng->state = oldstate * 6364136223846793005ULL + rng->inc; uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; uint32_t rot = oldstate >> 59u; return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); } int main() { pcg32_random_t rng; pcg32_srandom_r(&rng, 42u, 54u); // 初始化随机数生成器 for (int i = 0; i < 10; ++i) { uint32_t random_num = pcg32_random_r(&rng); // 生成随机数 printf("%u\n", random_num); } return 0; } ``` 在此示例中,我们定义了一个`pcg32_random_t`结构体来保存PCG算法的状态和步长。`pcg32_srandom_r`函数用于初始化随机数生成器的状态和步长,而`pcg32_random_r`函数则用于生成随机数。 在`main`函数中,我们首先创建一个`pcg32_random_t`结构体并使用`pcg32_srandom_r`函数初始化它。然后,我们使用`pcg32_random_r`函数生成10个随机数并打印出来。 请注意,这只是一个简单的示例代码,实际应用中可能需要根据具体需求进行适当的修改。此外,PCG算法还有其他变体和参数设置可供选择,您可以根据需要进行相应的调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值