Read/Write Bytes of Float in Js

Read/Write bytes of float in JS

Would this snippet help?

var parser = new BinaryParser
,forty = parser.encodeFloat(40.0,2,8)
,twenty = parser.encodeFloat(20.0,2,8);
console.log(parser.decodeFloat(forty,2,8).toFixed(1)); //=> 40.0
console.log(parser.decodeFloat(twenty,2,8).toFixed(1)); //=> 20.0

JavaScript - Convert bytes into float in a clean way

Is there a way to convert bytes back into the Float32

You don't need to convert it, it's already there! you just need to read it from the float32 view. However in your example you didn't save a reference to the float32 view...

Typed arrays work very differently to other numbers in JavaScript. The key is to think about the buffer and views independently - that is, Float32Array and Uint8Array are merely views into a buffer (a buffer is just a fixed sized contiguous block of memory, which is why typed arrays are so fast).

In your example when you called new Float32Array you passed it an array with a single number to initialise it, but you didn't pass it a buffer, this causes it to create a buffer for you of the appropriate length (4 bytes). When you called new Uint8Array you passed it a buffer instead, this doesn't cause it to merely copy the buffer, but it actually uses it directly. The below example is equivalent to yours, but retains all references and makes the above assertions more obvious:

const number = Math.PI

const buffer = new ArrayBuffer(4);
const f32 = new Float32Array(buffer); // [0]
const ui8 = new Uint8Array(buffer); // [0, 0, 0, 0]

f32[0] = number;
f32 // [3.1415927410125732]
ui8 // [219, 15, 73, 64]

ui8[3] = 1;
f32 // [3.6929245196445856e-38]
ui8 // [219, 15, 73, 1]

As you can see there is no need to "convert" above, as both views share the same buffer, any change via one view is instantly available in the other.

This is actually a good way to play with and understand floating point formats. Also use ui8[i].toString(2) to get the raw binary and use ui8[i] = parseInt('01010101', 2) set raw binary for each byte where i is 0-3. Note that you cannot set the raw binary through the f32 view as it will interpret your number numerically and break it into the significand and exponent, however you may want to do this to see how the numerical binary is converted into the float32 format.

Convert float to bytes in Javascript without Float32Array

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

Reading Raw bytes from a C float array in Javascript (conversion to JS array)

The answer was fairly simple but non-trivial.

First, I had to know what the byte data type incoming was. In this case it was a float type.

C float types allocate 4 bytes per address. Since I had an array of 32 floats (list size was 32), there were 4*32 byte locations to read from in the steam. All I had to do was iterate the buffer 4 positions at a time and read the next 4 bytes. Here's some sample code of how I did that:

var tmp = [];
for(var i =0; i < buf.length/4; i++) {
tmp.push(buf.readFloatBE(i*4));
}

So tmp contains my float array. There was some experimentation required, and the Javascript Buffer object has 2 prototype methods to read floats:

  • readFloatBE()
  • readFloatLE()

BE and LE stand for "Big Endian" and "Little Endian". This denotes the ordering of the bytes for numbers, and varies from compiler to compiler. In this case I had to use BE to get it working.

How to get the actual bytes of a javascript 64bit float

When you create a TypedArray of a certain type, say Int8Array like this:

let my = new Int8Array(1);

and assign a value to it, like this:

my[0] = 123456;

a conversion based on the this table is performed. So, for Int8Array the method ToInt8 is used with the last steps being:

...

Let int8bit be int modulo 2^8.

If int8bit ≥ 2^7, return int8bit − 2^8, otherwise return int8bit.

So, if we run these steps

Let int8bit be 123456 modulo 2^8 // 64
64 < 2^7 -> return int8bit, which is 64

So 64 is what you should expect:

console.log(my[0]); // 64

If you're interested in the actual bits order, check this answer for the algorithm or this article for the details of floating point.

JavaScript convert Array of 4 bytes into a float value from modbusTCP read

You could adapt the excellent answer of T.J. Crowder and use DataView#setUint8 for the given bytes.

var data =  [64, 226, 157, 10];
// Create a buffervar buf = new ArrayBuffer(4);// Create a data view of itvar view = new DataView(buf);
// set bytesdata.forEach(function (b, i) { view.setUint8(i, b);});
// Read the bits as a float; note that by doing this, we're implicitly// converting it from a 32-bit float into JavaScript's native 64-bit doublevar num = view.getFloat32(0);// Doneconsole.log(num);

Floating-point value from bytes reading completely wrong - Node.js

As you noted this is just an endian issue. Different systems expect bytes to be ordered in different ways, the most common ordering at the moment is little endian (used by Intel x86 compatible processors, and ARM systems are commonly set to use this mode).

Because JavaScript tries to be CPU agnostic it asks you to choose which order you want to interpret things. The BE in Buffer.readFloatBE stands for big-endian, and there's also a LE version which is what you probably want to use.

For example:

Buffer.from('0000003f','hex').readFloatLE()  // =>   0.5
Buffer.from('000020c1','hex').readFloatLE() // => -10.0

How to read a single-precision floating-point number from four bytes serialized by .NET's BinaryWriter

This is possible with node.js. Taken straight from the documentation:

var buf = new Buffer(4);

buf[0] = 0x00;
buf[1] = 0x00;
buf[2] = 0x80;
buf[3] = 0x3f;

console.log(buf.readFloatLE(0));

// 0x01

where LE refers to little-endian. There is a corresponding readFloatBE for big-endian.

Converting a string of packed bytes into an array of floats in Javascript

First, you have to convert a string into a buffer, and then create a Float32Array on that buffer. Optionally, spread it to create a normal Array:

str = '\x00\x00\x80?\x00\x00\x00@'
bytes = Uint8Array.from(str, c => c.charCodeAt(0))floats = new Float32Array(bytes.buffer)
console.log(floats)
console.log([...floats]);

Buffer reading and writing floats

readFloat in node is implemented in c++ and bytes are interpreted exactly the way your compiler stores/reads them. I doubt there is a bug here. What I think is that "7 digits" is incorrect assumption for float. This answer suggest 6 digits (and it's the value of std::numeric_limits<float>::digits10 ) so the result of readFloatBE is within expected error



Related Topics



Leave a reply



Submit