Search code examples
javaunsignedsigned

Why does ANDing a number convert between signed and unsigned presentation?


The code below displays a number stored as a Java byte value as hex, and in signed and unsigned representation. That might not be the correct wording. What I mean is, these numbers could be C style 1 byte unsigned char values. If I am interpreting these values (just so happens to be Java here but could be using any signed type in any language) then if the 'number' overflows into using the sign bit then the number will appear negative. But I can print as it would appear in unsigned interpretation by ANDing with 0xFF.

I understand how AND works but I can't understand how the ANDing presents as unsigned. Can someone please explain?

public class understand_casting {
    public static String printbinary(byte val) {
      int displayMask = 1 << 7;
          String str = new String();
          for(int bit = 1; bit <= 8; ++bit) {
              str += (val & displayMask) == 0 ? '0' : '1';
              val <<= 1; //shift one to left
          }
          return str;
    }

  public static void main(String[] args) {   
     System.out.printf("0x50=%s, as int=%d, as unsigned int=%d\n", printbinary((byte)0x50), (byte)0x50, ((byte)0x50 & 0xFF));
     System.out.printf("0x88=%s, as int=%d, as unsigned int=%d\n", printbinary((byte)0x88),(byte)0x88, ((byte)0x88 & 0xFF));
     System.out.printf("0x3E=%s, as int=%d, as unsigned int=%d\n", printbinary((byte)0x3E),(byte)0x3E, ((byte)0x3E & 0xFF));
     System.out.printf("0xB7=%s, as int=%d, as unsigned int=%d\n", printbinary((byte)0xB7), (byte)0xB7, ((byte)0xB7 & 0xFF));   
  }
}

I get this output:

0x50=01010000, as int=80, as unsigned int=80
0x88=10001000, as int=-120, as unsigned int=136
0x3E=00111110, as int=62, as unsigned int=62
0xB7=10110111, as int=-73, as unsigned int=183

Solution

  • As you might expect the binary of int 1 is

    0000 0000 0000 0000 0000 0000 0000 0001
    

    according to twos complement, you negate a number by inverting it and adding 1, so the binary of the signed int -1 in twos complement looks like

    1111 1111 1111 1111 1111 1111 1111 1111
    

    Any negative number is going to have the high bit set, while any positive number is going to have the high bit zero.

    For example, 0xff looks like and has a long string of 0's to the left

    0000 0000 0000 0000 0000 0000 1111 1111
    

    while -0xff looks like

    1111 1111 1111 1111 1111 1111 0000 0001
    

    When you mask using & you keep only the 1 bits that are present in both, so -2 & 0xff looks like

    1111 1111 1111 1111 1111 1111 1111 1110 |   -2
    0000 0000 0000 0000 0000 0000 1111 1111 | 0xff
    
    0000 0000 0000 0000 0000 0000 1111 1110 | -2 & 0xff = 0xfe
    

    ANDing with a positive value yields a positive value because the resulting high bit is always 0.