1

I'm trying to convert binary unsigned number to two's complement with javascript:

function bin_input_to_num(input) // 2 bit, input is string
{
    return ~Number('0b' + input) + '0b01'; // using ES6
}

console.log(bin_input_to_num('11'));  // actual: -3, expected: -1

I'm not sure what I'm missing.

(edit: I have carefully read through the marked possible duplicate question and answers, and it doesn't resolve my issue here)

Robert C. Holland
  • 1,651
  • 4
  • 24
  • 57

2 Answers2

1

Why not just check if it's in the negative range, then adjust accordingly? Something like this:

const compliment8bit = number => number < 128 ? number : -(256 - number);
Carl Smith
  • 3,025
  • 24
  • 36
0

In two's complement, you first need to decide whether the number is complemented or not. Since all parsing functions work with a minus instead of two's complement representation, we need to parse a positive/unsigned number and do some fiddling. If the input is not complemented (starts with 0), it's trivial, otherwise we have three choices:

  • complement the bit string, parse to a number, complement the number back to the intended value:

    console.assert(input.length == 2);
    console.assert(input[0] == '1');
    const compl = input.replace(/[01]/g, function(d){return +!+d;});
    const num = parseInt(compl, 2); // or Number('0b' + compl);
    return ~num; // or -(num + 1) or -num-1
    
  • extend to 32 bit, parse to a number, and cast to a signed 32 bit number with the builtin bitwise operators:

    console.assert(input.length == 2)
    console.assert(input[0] == '1');
    const input32 = "1".repeat(30)+input;
    const num = parseInt(input32, 2); // or Number('0b' + input32);
    return num >> 0; // or ~~num or num | 0
    
  • implement the wrap-around by subtraction (which can be combined with the non-complement case to a modulo operation to avoid branching):

    console.assert(input.length == 2);
    console.assert(input[0] == '1');
    const num = parseInt(input, 2); // or Number('0b' + input);
    return num - 4; // 2²
    
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks for the longer explanation. I don't understand the need for this extra step in method 2: `return num >> 0;` (double bit flips?) after integer has been parsed. Also, I am still not sure why my original code doesn't work. – Robert C. Holland Jun 25 '17 at 21:47
  • It takes the integer (which is still positive - uint32) and casts it to a signed integer (int32) by using a bitwise operator that "does nothing". – Bergi Jun 25 '17 at 22:08
  • How is that possible? (I really appreciate the effort to help me, but now I'm completely lost.) – Robert C. Holland Jun 25 '17 at 22:52
  • It's a property of all the bitwise operators. They cast all numbers they are working on from the standard 64 bit floating point representation to 32 bit integers. [It's a trick](https://stackoverflow.com/q/9049677/1048572). Don't use it if you're not comfortable with it. – Bergi Jun 25 '17 at 22:58