I'm doing some bitwise manipulation in a project and I wonder if the built-in typed arrays might save me some headache and maybe even give me a bit of a performance gain.
let bytes = [128, 129, 130, 131]
let uint32 = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]
//=> -2138996093
Can I use typed arrays to get the same answer ?
// not actually working !
let uint8bytes = Uint8Array.from(bytes)
let uint32 = Uint32Array.from(uint8bytes)[0]
//=> ideally i'd get the same value as above: -2138996093
Side question:
I found it strange that the uint32
above is negative – obviously not very ... unsigned as the name of the var suggests ...
If I mash together binary octets and parse it, I get the complimentary positive answer
// 128 129 130 131
let bin = '10000000' + '10000001' + '10000010' + '10000011'
let uint32 = Number.parseInt(bin,2)
console.log(uint32)
// 2155971203
It's no surprise that I can reverse the process to get the correct values out of each, but I don't understand why procedure 1 is negative but procedure 2 is positive.
let a = -2138996093;
let b = 2155971203;
// two's compliment, right?
console.log(a.toString(2)) // -1111111011111100111110101111101
console.log(b.toString(2)) // 10000000100000011000001010000011
console.log(a >> 24 & 255) // 128
console.log(a >> 16 & 255) // 129
console.log(a >> 8 & 255) // 130
console.log(a >> 0 & 255) // 131
console.log(b >> 24 & 255) // 128
console.log(b >> 16 & 255) // 129
console.log(b >> 8 & 255) // 130
console.log(b >> 0 & 255) // 131
JavaScript typed arrays are array-like objects that provide a mechanism for reading and writing raw binary data in memory buffers. Array objects grow and shrink dynamically and can have any JavaScript value. JavaScript engines perform optimizations so that these arrays are fast.
A typed array significantly simplifies the level of proof the engine needs to be able to optimise around it. A value returned from a typed array is certainly of a certain type, and engines can optimise for the result being that type.
The elements of a uint8 array can range from 0 to 255. Values outside this range are mapped to 0 or 255. If A is already an unsigned 8-bit integer array, uint8 has no effect. The fractional part of each value in A is discarded on conversion. This means, for example, that uint8(102.99) is 102, not 103.
You can use the set method. Create a new typed array with all the sizes. Example: var arrayOne = new Uint8Array([2,4,8]); var arrayTwo = new Uint8Array([16,32,64]); var mergedArray = new Uint8Array(arrayOne.
The best way to handle this is with a DataView - that way you can specify the endianness of the value you want to get - your code is using bigendian values for the int32
let bytes = [128, 129, 130, 131];
let uint8bytes = Uint8Array.from(bytes);
let dataview = new DataView(uint8bytes.buffer);
let int32le = dataview.getInt32(0, true); // second parameter truethy == want little endian
let int32be = dataview.getInt32(0); // second parameter absent or falsey == want big endian
console.log(int32le); // -2088599168
console.log(int32be); // -2138996093
The reason
let uint32 = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]
returns a SIGNED int is that the bitwise operators (<<
, |
) coerce the values to a signed 32 bit value
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With