Daniel Baulig, a co-worker at Facebook, told me a little trick related to jDataView function to convert from a uint8 to a int8 in Javascript.

Here's the version I had:

function getInt8() { var b = this.getUint8(); if (b > Math.pow(2, 7) - 1) { return b - Math.pow(2, 8); } return b; } |

Compare it to his version:

< <function getInt8() { return this.getUint8() << 24 >> 24; } |

I was really confused because it seems like it's doing a no-op. Here's the full explanation of why the two versions are working.

### How it works?

The following table (borrowed from Wikipedia) shows how various 8 bits values are in represented with bits and how they are interpreted in unsigned and signed (using two-complement rule).

Bits | uint8 | int8 |
---|---|---|

0000 0000 | 0 | 0 |

0000 0001 | 1 | 1 |

0000 0010 | 2 | 2 |

0111 1110 | 126 | 126 |

0111 1111 | 127 | 127 |

1000 0000 | 128 | −128 |

1000 0001 | 129 | −127 |

1000 0010 | 130 | −126 |

1111 1110 | 254 | −2 |

1111 1111 | 255 | −1 |

Javascript doesn't natively have a 8 bit integer type, it only has a 32 bits one. When you put a 8 bit integer into a 32 bits one, Javascript is going to fill the remaining bits on the left with zeros as the following table shows.

Bits | int32 |
---|---|

0000 0000 ... 0000 0000 | 0 |

0000 0000 ... 0000 0001 | 1 |

0000 0000 ... 0000 0010 | 2 |

0000 0000 ... 0111 1110 | 126 |

0000 0000 ... 0111 1111 | 127 |

0000 0000 ... 1000 0000 | 128 |

0000 0000 ... 1000 0001 | 129 |

0000 0000 ... 1000 0010 | 130 |

0000 0000 ... 1111 1110 | 254 |

0000 0000 ... 1111 1111 | 255 |

Unfortunately, this doesn't properly handle negative numbers. Because we use two-complement, we've got to fill all the bits with 1 for negative numbers in order to have the same number in a signed 32 bits representation.

Bits | int32 |
---|---|

0000 0000 ... 0000 0000 | 0 |

0000 0000 ... 0000 0001 | 1 |

0000 0000 ... 0000 0010 | 2 |

0000 0000 ... 0111 1110 | 126 |

0000 0000 ... 0111 1111 | 127 |

1111 1111 ... 1000 0000 | −128 |

1111 1111 ... 1000 0001 | −127 |

1111 1111 ... 1000 0010 | −126 |

1111 1111 ... 1111 1110 | −2 |

1111 1111 ... 1111 1111 | −1 |

So basically, we've got to fill the 24 remaining bits on the left with the same first bit we have: 0 for positive numbers and 1 for negative numbers.

This is when the trick comes into place. In javascript, there's a binary operator: `>>`

Sign-propagating right shift that moves all the bits to the right and fills the missing bits with the first bit.

So all we have to do is to put our 8 good digits to the far left using `<<`

and then use the previous trick to fill the bits with the proper ones 🙂

x | x < < 24 | (x << 24) >> 24 |
---|---|---|

0000 0000 ... 0000 0000 |
0000 0000 ... 0000 0000 |
0000 0000 ... 0000 0000 |

0000 0000 ... 0000 0001 |
0000 0001 ... 0000 0000 |
0000 0000 ... 0000 0001 |

0000 0000 ... 0000 0010 |
0000 0010 ... 0000 0000 |
0000 0000 ... 0000 0010 |

0000 0000 ... 0111 1110 |
0111 1110 ... 0000 0000 |
0000 0000 ... 0111 1110 |

0000 0000 ... 0111 1111 |
0111 1111 ... 0000 0000 |
0000 0000 ... 0111 1111 |

0000 0000 ... 1000 0000 |
1000 0000 ... 0000 0000 |
1111 1111 ... 1000 0000 |

0000 0000 ... 1000 0001 |
1000 0001 ... 0000 0000 |
1111 1111 ... 1000 0001 |

0000 0000 ... 1000 0010 |
1000 0010 ... 0000 0000 |
1111 1111 ... 1000 0010 |

0000 0000 ... 1111 1110 |
1111 1110 ... 0000 0000 |
1111 1111 ... 1111 1110 |

0000 0000 ... 1111 1111 |
1111 1111 ... 0000 0000 |
1111 1111 ... 1111 1111 |