Convert “float” to bytes in Javascript without Float32Array

后端 未结 3 1783
别跟我提以往
别跟我提以往 2020-12-09 06:10

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 by

相关标签:
3条回答
  • 2020-12-09 06:47

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

    0 讨论(0)
  • 2020-12-09 06:50

    See BinaryParser.encodeFloat here.

    0 讨论(0)
  • 2020-12-09 07:04

    You can use a JavaScript implementation of IEEE 754 like the one at http://ysangkok.github.io/IEEE-754/index.xhtml . It uses Emscripten and gmp.js.

    0 讨论(0)
提交回复
热议问题