转换“浮动";到没有 Float32Array 的 Javascript 中的字节
好的,我是一个相当烦人的情况,我无法访问诸如 Float32Array 之类的类型化数组,但仍然需要能够将 Javascript 数字转换为字节.现在,我可以很好地处理一个整数,但我不知道如何处理浮点值.
Okay so I'm an a fairly annoying situation where I don't have access to typed arrays such as Float32Array, but still need to be able to convert a Javascript number into bytes. Now, an integer I can handle just fine, but I have no idea how to do it for a floating point value.
我已经解决了相反的问题(将字节转换为浮点数),但是关于从浮点数转换为字节的文档非常稀缺,因为大多数语言只是让您读取指针或具有用于处理的通用类它.
I've solved the problem of doing it the other way around (bytes into a float), but documentation on converting from float to bytes is pretty scarce, as most language just let you read the pointer or have common classes for handling it.
理想情况下,我希望能够将浮点数转换为 4 字节和 8 字节表示,并选择使用哪一个.但是,可以简单地获取一个数字并将其输出为 8 字节的代码仍然很棒,因为我自己可能会从那里想出 32 位版本.
Ideally I'd like to be able to convert floats into both 4-byte and 8-byte representations, and choose which one to use. However, code that can simply take a number and spit it out as 8-bytes would still be great, as I can probably come up with the 32-bit version myself from there.
推荐答案
好的,所以我真的想通了,所以我将分享我的单精度和双精度解决方案.现在我不能保证它们 100% 符合标准,但它们不需要循环并且似乎工作得很好:
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:
单精度(给定一个十进制值输出一个具有二进制表示的单个 32 位大端整数):
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;
};
双精度(给定一个十进制值输出两个 32 位整数,二进制表示为大端序):
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 =)
相关文章