さて、実際にそれを理解したので、単精度と倍精度のソリューションを共有します。現在、それらが 100% 標準に準拠しているとは保証できませんが、ループを必要とせず、問題なく動作するようです:
単精度 (10 進値が与えられた場合、2 進数表現で 1 つの 32 ビット ビッグ エンディアン整数が出力されます):
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;
};
倍精度 (10 進値が 2 つの 32 ビット整数をビッグエンディアン順のバイナリ表現で出力する場合):
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];
};
コピー/貼り付けの間違いをお詫びします。また、コードはエンディアンの処理を省略していますが、追加はかなり簡単です。
提案を投稿してくれた皆さんに感謝しますが、速度を上げるためにできるだけループを避けたかったので、ほとんど自分で考え出すことになりました。それはまだ正確に猛烈に速いわけではありませんが、そうするでしょう =)