1

How to convert a number from unsigned to signed?

signed: -32768 to 32767 unsigned: 0 to 65535

I am solving the problem in JavaScript. The situation is that I have a number that goes e.g. from 0 to 65535 and I want to convert it to a reasonable signed value.

e.g.: 65535 should become -1.

Please do not use any bit related operations but something arithmetical.

I guess this should be language independent assuming that we use a data type that is big enough.

Update: Implementation according to the answer further down:

function convertWordToShort(ival) {
    if (isNaN(ival) === false) {
        if (ival > 32767) {
            ival = ival - 65536;
        }
    }
    return ival;
}
function convertShortToWord(ival) {
    if (isNaN(ival) === false) {
        if (ival < 0) {
            ival = ival + 65536;
        }
    }
    return ival;
}
function convertIntToDWord(ival) {
    if (isNaN(ival) === false) {
        if (ival < 0) {
            ival = ival + 4294967296;
        }
    }
    return ival;
}
function convertDWordToInt(ival) {
    if (isNaN(ival) === false) {
        if (ival > 2147483647) {
            ival = ival - 4294967296;
        }
    }
    return ival;
}
Matthias
  • 1,386
  • 3
  • 24
  • 59
  • I don't quite get your rules, why is 65535 = -1? – Agi Sferro Mar 13 '13 at 15:34
  • That is because if you do that conversion in C programming language this is exactly what comes out. UInt16 x = 65535; var y = (Int16)x; // y = -1 – Matthias Mar 13 '13 at 15:36
  • 2
    Different languages have their own rules about what to do in these situations. – teppic Mar 13 '13 at 15:39
  • 1
    @Matthias Your "C" syntax is pretty exotic. :) – unwind Mar 13 '13 at 15:42
  • Its C but with a # at the end I guess. unsigned short x = 65535; short y = (short)x//y=-1 – Matthias Mar 13 '13 at 15:54
  • @teppic could you give us an example? – Matthias Mar 13 '13 at 16:02
  • @Matthias: well in C, signed integer overflow is undefined, but unsigned is OK. That may or not be the same in Javascript. And what happens to a number when it overflows can vary. – teppic Mar 13 '13 at 16:31
  • @teppic signed integer overflow is undefined by specification, but this seems to be a bit an academical side note since most plafroms will do the same. – Matthias Mar 13 '13 at 16:55
  • http://codepad.org/hzKWkEu1 – Matthias Mar 13 '13 at 17:01
  • @Matthias It's purely academical as long as compiler writers don't start to take advantage of the fact that signed integer overflow is not supposed to occur to perform some obscure optimization (and tell their users that they should have written standard-compliant code in the first place). See e.g. http://stackoverflow.com/questions/2892477/gcc-optimization-bug-and-its-practial-implication-to-project – Virgile Mar 13 '13 at 17:51
  • Thank you folks for all your comments. – Matthias Mar 13 '13 at 18:55

3 Answers3

8

Just test if the number is over halfway, then subtract the modulus.

if(x > 32767) {x = x - 65536;}
UncleO
  • 8,299
  • 21
  • 29
2

In the case that you would be looking for bitwise operation related answers, you could try the following:

  • to convert something akin to a 16 bit unsigned integer (i.e 0 <= n <= 65535) to a 16 bit signed one:
(number << 16) >> 16
  • Or:
new Int16Array([number])[0]

Where number in both cases is your 16 bit number.

As a side note the reason the first solution works is because if you bit shift to the right 16 times, the most significant bit of your 16 bit number will actually become the most significant bit of the 32 bit JavaScript integer (so if the most significant bit was a 1, it'd make the number negative), and so when you shift it to the left 16 times it'd shift while keeping the standard 2s complement form and retain the value/sign it gained from being shifted to the right previously, see this Wikipedia article for more:
https://en.m.wikipedia.org/wiki/Arithmetic_shift

warmtea
  • 107
  • 9
-1

function signed(bits, value) { return value & (1 << (bits - 1)) ? value - (1 << bits) : value; }

signed(8, 0xFF); // returns -1

signed(16, 0xFF); // returns 255