Okay, so I actually figured it out, so I'll share my solution for single and double precision. Now I can't guarantee that they're 100% standards compliant, but they require no loops and seem to work just fine:
Single precision (given a decimal value outputs a single 32-bit big endian integer with the binary representation):
function toFloat32(value) {
var bytes = 0;
switch (value) {
case Number.POSITIVE_INFINITY: bytes = 0x7F800000; break;
case Number.NEGATIVE_INFINITY: bytes = 0xFF800000; break;
case +0.0: bytes = 0x40000000; break;
case -0.0: bytes = 0xC0000000; break;
default:
if (Number.isNaN(value)) { bytes = 0x7FC00000; break; }
if (value <= -0.0) {
bytes = 0x80000000;
value = -value;
}
var exponent = Math.floor(Math.log(value) / Math.log(2));
var significand = ((value / Math.pow(2, exponent)) * 0x00800000) | 0;
exponent += 127;
if (exponent >= 0xFF) {
exponent = 0xFF;
significand = 0;
} else if (exponent < 0) exponent = 0;
bytes = bytes | (exponent << 23);
bytes = bytes | (significand & ~(-1 << 23));
break;
}
return bytes;
};
Double precision (given a decimal value outputs two 32-bit integers with the binary representation in big-endian order):
function toFloat64(value) {
if ((byteOffset + 8) > this.byteLength)
throw "Invalid byteOffset: Cannot write beyond view boundaries.";
var hiWord = 0, loWord = 0;
switch (value) {
case Number.POSITIVE_INFINITY: hiWord = 0x7FF00000; break;
case Number.NEGATIVE_INFINITY: hiWord = 0xFFF00000; break;
case +0.0: hiWord = 0x40000000; break;
case -0.0: hiWord = 0xC0000000; break;
default:
if (Number.isNaN(value)) { hiWord = 0x7FF80000; break; }
if (value <= -0.0) {
hiWord = 0x80000000;
value = -value;
}
var exponent = Math.floor(Math.log(value) / Math.log(2));
var significand = Math.floor((value / Math.pow(2, exponent)) * Math.pow(2, 52));
loWord = significand & 0xFFFFFFFF;
significand /= Math.pow(2, 32);
exponent += 1023;
if (exponent >= 0x7FF) {
exponent = 0x7FF;
significand = 0;
} else if (exponent < 0) exponent = 0;
hiWord = hiWord | (exponent << 20);
hiWord = hiWord | (significand & ~(-1 << 20));
break;
}
return [hiWord, loWord];
};
Apologies for any mistakes in copy/pasting, also the code ommits any handling of endianness, though it's fairly easy to add.
Thanks to everyone posting suggestions, but I ended up figuring out mostly on my own, as I wanted to avoid looping as much as possible for speed; it's still not exactly blazingly fast but it'll do =)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…