//#region src/distribution/internals/uniformIntInternal.ts /** * Uniformly generate number in range [0 ; rangeSize[ * With rangeSize <= 0x100000000 * @internal */ function uniformIntInternal(rng, rangeSize) { const MaxAllowed = rangeSize > 2 ? ~~(4294967296 / rangeSize) * rangeSize : 4294967296; let deltaV = rng.next() + 2147483648; while (deltaV >= MaxAllowed) deltaV = rng.next() + 2147483648; return deltaV % rangeSize; } //#endregion //#region src/distribution/internals/ArrayInt64.ts /** * We only accept safe integers here * @internal */ function fromNumberToArrayInt64(out, n) { if (n < 0) { const posN = -n; out.sign = -1; out.data[0] = ~~(posN / 4294967296); out.data[1] = posN >>> 0; } else { out.sign = 1; out.data[0] = ~~(n / 4294967296); out.data[1] = n >>> 0; } return out; } /** * Substract two ArrayInt of 64 bits on 64 bits. * With arrayIntA - arrayIntB >= 0 * @internal */ function substractArrayInt64(out, arrayIntA, arrayIntB) { const lowA = arrayIntA.data[1]; const highA = arrayIntA.data[0]; const signA = arrayIntA.sign; const lowB = arrayIntB.data[1]; const highB = arrayIntB.data[0]; const signB = arrayIntB.sign; out.sign = 1; if (signA === 1 && signB === -1) { const low = lowA + lowB; const high = highA + highB + (low > 4294967295 ? 1 : 0); out.data[0] = high >>> 0; out.data[1] = low >>> 0; return out; } let lowFirst = lowA; let highFirst = highA; let lowSecond = lowB; let highSecond = highB; if (signA === -1) { lowFirst = lowB; highFirst = highB; lowSecond = lowA; highSecond = highA; } let reminderLow = 0; let low = lowFirst - lowSecond; if (low < 0) { reminderLow = 1; low = low >>> 0; } out.data[0] = highFirst - highSecond - reminderLow; out.data[1] = low; return out; } //#endregion //#region src/distribution/internals/uniformArrayIntInternal.ts /** * Uniformly generate ArrayInt64 in range [0 ; rangeSize[ * * @remarks * In the worst case scenario it may discard half of the randomly generated value. * Worst case being: most significant number is 1 and remaining part evaluates to 0. * * @internal */ function uniformArrayIntInternal(rng, out, rangeSize) { const maxIndex0 = rangeSize[0] + 1; out[0] = uniformIntInternal(rng, maxIndex0); out[1] = uniformIntInternal(rng, 4294967296); while (out[0] >= rangeSize[0] && (out[0] !== rangeSize[0] || out[1] >= rangeSize[1])) { out[0] = uniformIntInternal(rng, maxIndex0); out[1] = uniformIntInternal(rng, 4294967296); } return out; } //#endregion //#region src/distribution/uniformInt.ts const safeNumberMaxSafeInteger = Number.MAX_SAFE_INTEGER; const sharedA = { sign: 1, data: [0, 0] }; const sharedB = { sign: 1, data: [0, 0] }; const sharedC = { sign: 1, data: [0, 0] }; const sharedData = [0, 0]; function uniformLargeIntInternal(rng, from, to, rangeSize) { const rangeSizeArrayIntValue = rangeSize <= safeNumberMaxSafeInteger ? fromNumberToArrayInt64(sharedC, rangeSize) : substractArrayInt64(sharedC, fromNumberToArrayInt64(sharedA, to), fromNumberToArrayInt64(sharedB, from)); if (rangeSizeArrayIntValue.data[1] === 4294967295) { rangeSizeArrayIntValue.data[0] += 1; rangeSizeArrayIntValue.data[1] = 0; } else rangeSizeArrayIntValue.data[1] += 1; uniformArrayIntInternal(rng, sharedData, rangeSizeArrayIntValue.data); return sharedData[0] * 4294967296 + sharedData[1] + from; } /** * Uniformly generate random integer values between `from` (included) and `to` (included) * * @param rng - Instance of RandomGenerator to extract random values from * @param from - Lower bound of the range (included) * @param to - Upper bound of the range (included) * * @public */ function uniformInt(rng, from, to) { const rangeSize = to - from; if (rangeSize <= 4294967295) return uniformIntInternal(rng, rangeSize + 1) + from; return uniformLargeIntInternal(rng, from, to, rangeSize); } //#endregion export { uniformInt };