Since the following code is quite simple and functionally equivalent to the division method, here is the alternate method of altering the bits. (This code is copied and modified from @T.J. Crowder's very helpful answer).
// A buffer with just the right size to convert to Float64
let buffer = new ArrayBuffer(8);
// View it as an Int8Array and fill it with 8 random ints
let ints = new Int8Array(buffer);
window.crypto.getRandomValues(ints);
// Set the sign (ints[7][7]) to 0 and the
// exponent (ints[7][6]-[6][5]) to just the right size
// (all ones except for the highest bit)
ints[7] = 63;
ints[6] |= 0xf0;
// Now view it as a Float64Array, and read the one float from it
let float = new DataView(buffer).getFloat64(0, true) - 1;
document.body.innerHTML = "The number is " + float;
Explanation:
The format of a IEEE754 double is 1 sign bit (ints[7][7]
), 11 exponent bits (ints[7][6]
to ints[6][5]
), and the rest as mantissa (which holds the values). The formula to compute is
To set the factor to 1, the exponent needs to be 1023. It has 11 bits, thus the highest-order bit gives 2048. This needs to be set to 0, the other bits to 1.