Why am I not able to mask 32 bits on a long data type in Java

2

I cannot figure out why this works. I am attempting to mask the least significant 32 bits of java on a long but it does not properly AND the 33rd and 34th bit and further. Here is my example

class Main {
  public static void main(String[] args) {
    long someVal = 17592096894893l; //hex  0xFFFFAAFAFAD
    long mask = 0xFF; //binary
    long result = mask & someVal;                  

    System.out.println("Example 1 this works on one byte");
    System.out.printf("\n%x %s", someVal, Long.toBinaryString(someVal) );
    System.out.printf("\n%x %s", result, Long.toBinaryString(result) );

    long someVal2 = 17592096894893l; //hex  0xFFFFAAFAFAD
    mask = 0xFFFFFFFF; //binary
    result = mask & someVal2; 
    System.out.println("\nExample 2 - this does not work");
    System.out.printf("\n%x %s", someVal2, Long.toBinaryString(someVal2) );
    System.out.printf("\n%x %s", result, Long.toBinaryString(result) );
  }
}

I was expecting the results to drop the most significant byte to be a zero since the AND operation did it on 32 bits. Here is the output I get.

Example 1 - this works
ffffaafafad 11111111111111111010101011111010111110101101
ad 10101101
Example 2 - this does not work

ffffaafafad 11111111111111111010101011111010111110101101
ffffaafafad 11111111111111111010101011111010111110101101

I would like to be able to mask the first least significant 4 bytes of the long value.

java
binary
bit-manipulation
masking
asked on Stack Overflow Apr 27, 2019 by FernandoZ

1 Answer

2

I believe what you’re seeing here is the fact that Java converts integers to longs using sign extension.

For starters, what should this code do?

int myInt = -1;
long myLong = myInt;
System.out.println(myLong);

This should intuitively print out -1, and that’s indeed what happens. I mean, it would be kinda weird if in converting an int to a long, we didn’t get the same number we started with.

Now, let’s take this code:

int myInt = 0xFFFFFFFF;
long myLong = myInt;
System.out.println(myLong);

What does this print? Well, 0xFFFFFFFF is the hexadecimal version of the signed 32-bit number -1. That means that this code is completely equivalent to the above code, so it should (and does) print the same value, -1.

But the value -1, encoded as a long, doesn’t have representation 0x00000000FFFFFFFF. That would be 232 - 1, not -1. Rather, since it’s 64 bits long, -1 is represented as 0xFFFFFFFFFFFFFFFFF. Oops - all the upper bits just got activated! That makes it not very effective as a bitmask.

The rule in Java is that if you convert an int to a long, if the very first bit of the int is 1, then all 32 upper bits of the long will get set to 1 as well. That’s in place so that converting an integer to a long preserves the numeric value.

If you want to make a bitmask that’s actually 64 bits long, initialize it with a long literal rather than an int literal:

mask = 0xFFFFFFFFL; // note the L

Why does this make a difference? Without the L, Java treats the code as

  1. Create the integer value 0xFFFFFFFF = -1, giving 32 one bits.
  2. Convert that integer value into a long. To do so, use sign extension to convert it to the long value -1, giving 64 one bits in a row.

However, if you include the L, Java interprets things like this:

  1. Create the long value 0xFFFFFFFF = 232 - 1, which is 32 zero bits followed by 32 one bits.
  2. Assign that value to mask.

Hope this helps!

answered on Stack Overflow Apr 27, 2019 by templatetypedef • edited Apr 28, 2019 by templatetypedef

User contributions licensed under CC BY-SA 3.0