Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 781
Haravikk Avatar asked Apr 10 '13 20:04

Haravikk


People also ask

Can we convert float to byte?

Float to Byte Array Conversion As we know, the size of a float in Java is 32 bit which is similar to an int. So we can use floatToIntBits or floatToRawIntBits functions available in the Float class of Java. And then shift the bits to return a byte array.

Can we convert float to byte in Java?

byteValue() is a built-in method in Java that returns the value of this Float as a byte(by casting to a byte). Basically it used for narrowing primitive conversion of Float type to a byte value.

What is a float 32 array?

The Float32Array typed array represents an array of 32-bit floating point numbers (corresponding to the C float data type) in the platform byte order. If control over byte order is needed, use DataView instead. The contents are initialized to 0 .

How many bytes is an float?

Floating-point numbers use the IEEE (Institute of Electrical and Electronics Engineers) format. Single-precision values with float type have 4 bytes, consisting of a sign bit, an 8-bit excess-127 binary exponent, and a 23-bit mantissa.


1 Answers

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

like image 162
Haravikk Avatar answered Oct 12 '22 10:10

Haravikk