Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
773 views
in Technique[技术] by (71.8m points)

floating point - Convert "float" to bytes in Javascript without Float32Array

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.

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 =)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...