// Uint32 的取值空间大小为 2^32。 // Random 模块中的基础随机换算都会用到这一个范围常量。 const internalRandomUint32Range = 0x1_0000_0000 /** * @description 取得一个随机 Uint32 值。 * * 当运行时提供 `crypto.getRandomValues` 时,使用该随机源生成结果;否则回退到 `Math.random`。 * 该函数适合作为 Random 模块内外共享的基础随机整数入口。 * * @example * ``` * const value = getRandomUint32() * // Expect: true * const example1 = Number.isInteger(value) && value >= 0 && value < 0x1_0000_0000 * ``` */ export const getRandomUint32 = (): number => { if (globalThis.crypto !== undefined && typeof globalThis.crypto.getRandomValues === "function") { const buffer = new Uint32Array(1) globalThis.crypto.getRandomValues(buffer) return buffer[0]! } return Math.floor(Math.random() * internalRandomUint32Range) } /** * @description 取得一个 `0` 到 `1` 之间的随机小数,包含下界,不包含上界。 * * 该函数基于统一的 Uint32 随机源换算得到,适合作为随机数字与随机整数逻辑的公共基础。 * * @example * ``` * const value = getRandomUnitValue() * // Expect: true * const example1 = value >= 0 && value < 1 * ``` */ export const getRandomUnitValue = (): number => { return getRandomUint32() / internalRandomUint32Range } /** * @description 将随机整数均匀映射为索引。 * * 若直接对 `alphabetLength` 取模,在长度不能整除 `2^32` 时会产生轻微偏差,因此这里使用拒绝采样,丢弃落在尾部残余区间的随机值。 * * @example * ``` * const index = getRandomIndex(3) * // Expect: true * const example1 = Number.isInteger(index) && index >= 0 && index < 3 * ``` */ export const getRandomIndex = (length: number): number => { const limit = internalRandomUint32Range - (internalRandomUint32Range % length) while (true) { const value = getRandomUint32() if (value < limit) { return value % length } } }