I have saw this but it does not provide an answer.
I would want something like this:
let randomBigInt = generateRandomBigInt(0, 920392947394829032030943);
console.log(randomBigInt); // 4893848594594
I have saw this but it does not provide an answer.
I would want something like this:
let randomBigInt = generateRandomBigInt(0, 920392947394829032030943);
console.log(randomBigInt); // 4893848594594
On
Here's a solution using crypto.getRandomValues as the random number source to generate random bigint over a nearly arbitrarily large (524288 bit) range without losing precision.
Of course, it rapidly becomes infeasible to test that it is non-skewed.
function mask(arr: Uint8Array, numBits: number) {
let idx = 0;
let b = numBits;
while (idx < arr.length) {
arr[idx] =
b <= 0 ? 0 : b > 0 && b < 8 ? arr[idx] & ((1 >> b) - 1) : arr[idx];
++idx;
b -= 8;
}
}
function getBitCount(v: bigint) {
let x = v;
let c = 0;
do {
++c;
x >>= 1n;
} while (x > 0n)
return c;
}
function bigRandomInRange(v1: bigint, v2: bigint) {
const min = v1 > v2 ? v2 : v1;
const r = v1 - v2;
const range = r < 0 ? -r : r;
if (range === 0n) {
return min;
}
const bitCount = getBitCount(range);
const byteCount = Math.ceil(bitCount / 8);
const arr = new Uint8Array(byteCount);
for (; ;) {
crypto.getRandomValues(arr);
mask(arr, bitCount);
const v = arr.reduce(
(acc, curr, i) => (1n << (BigInt(i) * 8n)) * BigInt(curr) + acc, 0n);
if (v < range) {
return min + v;
}
}
}
On
function randomBigInt(max: bigint | number | string): bigint;
function randomBigInt(min: bigint | number | string, max: bigint | number | string): bigint;
function randomBigInt(min: bigint | number | string, max?: bigint | number | string): bigint {
if (max === undefined) return randomBigInt(0n, min);
// choose if you want to allow not-bigints yourself
// this wrapper allows `bigint | number | string` (you may want to keep at least `bigint | number`
min = BigInt(min);
max = BigInt(max);
// choose what happens when input order is invalid (e.g. throw error)
// this wrapper keeps `min` in and `max` out of generatable numbers
if (min <= max)
return min + _generateRandomBigInt(max - min);
else
return max - 1 - _generateRandomBigInt(min - max);
}
/**
* This is tha basic function to generate random bigint.
* @param max exclusive maximum
* (c) <CC-BY-SA-4.0 or Unlicense> Dimava, 2023
*/
function _generateRandomBigInt(max: bigint): bigint {
if (max < 0) throw new Error("generateRandomBigInt cannot generate negative BigInt");
if (max === 0n) return 0n;
const POWER = 64n;
const FILTER = (1n << POWER) - 1n;
// 1. Create an BigInt64Array representation of max number
let num = max;
const maxList: bigint[] = [];
while (num) {
maxList.unshift(num & FILTER);
num >>= POWER;
}
const maxArray = BigInt64Array.from(maxList);
// 2. Generate the random number
const rndArray = crypto.getRandomValues(maxArray.slice());
// 3. Trim the random number highest bits
// to reduce failure rate to <50%
let trim = 1n;
while (maxArray[0] > trim) trim <<= 1n;
trim--;
rndArray[0] &= trim;
// 4. Convert to bigint
let rnd = 0n;
for (let i = 0; i < rndArray.length; i++) {
rnd <<= POWER;
rnd += rndArray[i];
}
// 5. Check for failure (the random number being higher then max)
// and retry if needed
if (rnd >= max) return _generateRandomBigInt(max);
return rnd;
}
console.log(randomBigInt(1000n))
console.log(randomBigInt(1000n, 2000n))
console.log(randomBigInt(-1000n, 0n))
You can generate a random float, which will be between 0 and 1. You can then multiply it to be in the BigInt limits. Passing it in the
const bigIntValue = BigInt(yourRandomMultipliedValue)will convert it into a bigint type.