24

I am receiving and sending a decimal representation of two little endian numbers. I would like to:

  • shift one variable 8 bits left
  • OR them
  • shift a variable number of bits
  • create 2 8 bit numbers representing the first and second half of the 16 bit number.

javascript (according to https://developer.mozilla.org/en/JavaScript/Reference/Operators/Bitwise_Operators) uses big endian representation when shifting...

endianness is a bit foreign to me (I am only 90 percent sure that my outlined steps are what i want.) so swapping is a bit dizzying. please help! I only really need to know how to swap the order in an efficient manner. (I can only think of using a for loop on a toString() return value)

griotspeak
  • 13,022
  • 13
  • 43
  • 54

4 Answers4

43
function swap16(val) {
    return ((val & 0xFF) << 8)
           | ((val >> 8) & 0xFF);
}

Explanation:

  1. Let's say that val is, for example, 0xAABB.
  2. Mask val to get the LSB by &ing with 0xFF: result is 0xBB.
  3. Shift that result 8 bits to the left: result is 0xBB00.
  4. Shift val 8 bits to the right: result is 0xAA (the LSB has "dropped off" the right-hand side).
  5. Mask that result to get the LSB by &ing with 0xFF: result is 0xAA.
  6. Combine the results from steps 3 and step 5 by |ing them together:
    0xBB00 | 0xAA is 0xBBAA.

function swap32(val) {
    return ((val & 0xFF) << 24)
           | ((val & 0xFF00) << 8)
           | ((val >> 8) & 0xFF00)
           | ((val >> 24) & 0xFF);
}

Explanation:

  1. Let's say that val is, for example, 0xAABBCCDD.
  2. Mask val to get the LSB by &ing with 0xFF: result is 0xDD.
  3. Shift that result 24 bits to the left: result is 0xDD000000.
  4. Mask val to get the second byte by &ing with 0xFF00: result is 0xCC00.
  5. Shift that result 8 bits to the left: result is 0xCC0000.
  6. Shift val 8 bits to the right: result is 0xAABBCC (the LSB has "dropped off" the right-hand side).
  7. Mask that result to get the second byte by &ing with 0xFF00: result is 0xBB00.
  8. Shift val 24 bits to the right: result is 0xAA (everything except the MSB has "dropped off" the right-hand side).
  9. Mask that result to get the LSB by &ing with 0xFF: result is 0xAA.
  10. Combine the results from steps 3, 5, 7 and 9 by |ing them together:
    0xDD000000 | 0xCC0000 | 0xBB00 | 0xAA is 0xDDCCBBAA.
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • 1
    so, this seems to work...is there a plain spoken explanation or should i just take it and run? – griotspeak Mar 16 '11 at 03:23
  • 1
    @griotspeak: I've edited to attempt an explanation, although I suspect that it would make more sense for you to read the wikipedia articles on [endianness](http://en.wikipedia.org/wiki/Endianness) and [bitwise operations](http://en.wikipedia.org/wiki/Bitwise_operation) instead. – LukeH Mar 16 '11 at 10:45
  • ok, this wasn't actually what i wanted, but i think i am simply being unclear. I need a literal reversal of the first 8(or 16?) bits. I think this answer gets me close enough to work it out. – griotspeak Mar 16 '11 at 19:27
  • 1
    `function swap8(val) { return ((val & 0x1) << 7) | ((val & 0x2) << 5) | ((val & 0x4) << 3) | ((val & 0x8) << 1) | ((val >> 1) & 0x8) | ((val >> 3) & 0x4) | ((val >> 5) & 0x2) | ((val >> 7) & 0x1); }` was my final solution – griotspeak Mar 16 '11 at 20:32
  • In case this helps anyone, the `swap16()` function alone was not handling signed integers correctly. I had to combine it with [this](http://stackoverflow.com/questions/7461204/javascript-unsigned-short-to-signed-short) in order to get everything working correctly: `((((val & 0xFF) << 8) | ((val >> 8) & 0xFF)) << 16) >> 16` – martinez314 Jan 16 '14 at 21:02
  • 1
    @whiskeyspider mentioned the sign problem already. Here's what I ended up with instead: `function swap16(val) { var x = ((val & 0xFF) << 8) | ((val >> 8) & 0xFF); if (x < 0) x = (x & 0x7FFF) + 0x8000; return x; } function swap32(val) { var x = ((val & 0xFF) << 24) | ((val & 0xFF00) << 8) | ((val >> 8) & 0xFF00) | ((val >> 24) & 0xFF); if (x < 0) x = (x & 0x7FFFFFFF) + 0x80000000; return x; }` – sarme Mar 17 '14 at 19:13
9

Such function can be used to change endianness in js:

const changeEndianness = (string) => {
        const result = [];
        let len = string.length - 2;
        while (len >= 0) {
          result.push(string.substr(len, 2));
          len -= 2;
        }
        return result.join('');
}

changeEndianness('AA00FF1234'); /// '3412FF00AA'
Mihey Mik
  • 1,643
  • 13
  • 18
1

Use the << (bit shift) operator. Ex: 1 << 2 == 4.

I really think that the underlying implementation of JavaScript will use whatever endianess the platform it is running on is using. Since you cannot directly access memory in JavaScript you won't ever have to worry about how numbers are represented physically in memory. Bit shifting integer values always yield the same result no matter the endianess. You only see a difference when looking at individual bytes in memory using pointers.

Martin
  • 224
  • 2
  • 9
  • I am literally being given a decimal representation of a little endian number and need to give back a decimal representation of a little ending number. A display is being driven by the binary representation... so it matters. – griotspeak Mar 16 '11 at 03:26
  • i think i see what you were getting at, and i think that in many cases you would be correct. the number i get and give is meant to turn 8 lights on from left to right so i will, essentially, be looking at the individual bytes. – griotspeak Mar 16 '11 at 20:39
0

Here is a oneliner for arrays to swap between big and little endian (and vise versa). The swapping is done using reverse on byte level. I guess for large arrays, it is more efficient than looping over scalar swap function.

function swapbyte(x) {
    return new Float64Array(new Int8Array(x.buffer).reverse().buffer).reverse()
}

// Example
buf = new ArrayBuffer(16);        // for 2 float64 numbers
enBig = new Float64Array(buf);
enBig[0] = 3.2073756306779606e-192;
enBig[1] = 2.7604354232023903e+199;

enLittle = swapbyte(enBig)

// two famous numbers are revealed
console.log(enLittle)
// Float64Array [ 6.283185307179586, 2.718281828459045 ]

// swapping again yields the original input
console.log(swapbyte(enLittle))
// Float64Array [ 3.2073756306779606e-192, 2.7604354232023903e+199 ]