在Javascript中将“float”转换为字节,不使用Float32Array

8

好的,我遇到了一个相当麻烦的情况,即我没有访问诸如Float32Array之类的类型数组的权限,但仍然需要将JavaScript数字转换为字节。对于整数,我可以很好地处理,但是对于浮点值,我不知道该怎么做。

我已经解决了反过来做的问题(将字节转换为浮点数),但是关于从浮点数转换为字节的文档非常少,因为大多数语言都可以读取指针或具有处理它的常见类。

理想情况下,我希望能够将浮点数转换为4字节和8字节表示,并选择使用哪个。但是,只要能够简单地将数字输出为8字节的代码仍然很棒,因为我可能可以从中得出32位版本。


2
toString(2) 有帮助吗?(42).toString(2) - Mohsen
1
你可能也会发现 Number.toExponential 有一些用处。 - Paul S.
3个回答

9

好的,我已经想出解决方案了,接下来分享一下我针对单精度和双精度的解决方法。虽然我无法保证它们100%符合标准,但是它们不需要循环,似乎可以正常工作:

单精度(给定十进制值,输出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;
};

双精度(给定一个十进制值,输出两个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];
};

抱歉如果复制/粘贴中有任何错误,代码也省略了对字节序的处理,但很容易添加。

感谢所有提出建议的人,但我最终大部分是自己想出来的,因为我想尽可能避免循环以提高速度;虽然它仍不是非常快,但已经足够了=)


1
请参见 BinaryParser.encodeFloat 此处

该库使用 with(还有其他一些不被允许的写法),因此不符合 strict 规范!使用时要小心! - Qix - MONICA WAS MISTREATED

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接