0

I was recently looking into some problems with but manipulation in Java and I came up with two questions.

1) Firstly, I came up to the problem of flipping all the bits in a number.

I found this solution:

public class Solution {
    public int flipAllBits(int num) {
        int mask = (1 << (int)Math.floor(Math.log(num)/Math.log(2))+1) - 1;
        return num ^ mask;
    }
}

But what happens when k = 32 bits? Can the 1 be shifted 33 times?

What I understand from the code (although it doesn't really make sense), the mask is 0111111.(31 1's)....1 and not 32 1's, as someone would expect. And therefore when num is a really large number this would fail.

2) Another question I had was determining when something is a bit sequence in 2s complement or just a normal bit sequence. For example I read that 1010 when flipped is 0110 which is -10 but also 6. Which one is it and how do we know?

Thanks.

pavlos163
  • 2,730
  • 4
  • 38
  • 82
  • Possible duplicate of [How are integers internally represented at a bit level in Java?](http://stackoverflow.com/questions/13422259/how-are-integers-internally-represented-at-a-bit-level-in-java) – Andrew Jenkins Jan 31 '17 at 19:39
  • That one doesn't really answer either of the two questions directly, but the two probably should be separate questions and possibly clarified. – Douglas Daseeco Jan 31 '17 at 20:05
  • As a side note, to flip all the bits, you can simply use the `~` operator. – Chai T. Rex Feb 01 '17 at 01:12

2 Answers2

1

1) The Math object calls are not necessary. Flipping all the bits in any ordinal type in Java (or C) is not an arithmatic operation. It is a bitwise operation. Using the '^' operator, simply using 1- as an operand will work regardless of the sizeof int in C/C++ or a Java template with with the ordinal type as a parameter T. The tilde '~' operator is the other option.

T i = 0xf0f0f0f0;
System.out.println(T.toHexString(i));
i ^= -1;
System.out.println(T.toHexString(i));
i = ~ i;
System.out.println(T.toHexString(i));

2) Since the entire range of integers maps to the entire range of integers in a 2's compliment transform, it is not possible to detect whether a number is or is not 2's complement unless one knows the range of numbers from which the 2's complement might be calculated and the two sets (before and after) are mutually exclusive.

Douglas Daseeco
  • 3,475
  • 21
  • 27
0

That mask computation is fairly inscrutable, I'm going to guess that it (attempts to, since you mention it's wrong) make a mask up to and including the highest set bit. Whether that's useful for "flipping all bits" is an other possible point of discussion, since to me at least, "all bits" means all 32 of them, not some number that depends on the value. But if that's what you want then that's what you want. Especially combined with that second question, that looks like a mistake to me, so you'd be implementing the wrong thing from the start - see near the bottom.

Anyway, the mask can be generated with some reasonably nice bitmath, which does not create any doubt about possible edge cases (eg Math.log(0) is probably bad, and k=32 corresponds with negative numbers which are also probably bad to put into a log):

int m = num | (num >> 16);
m |= m >> 8;
m |= m >> 4;
m |= m >> 2;
m |= m >> 1;
return num ^ m;

Note that this function has odd properties, it almost always returns an unsigned-lower number than went in, except at 0. It flips bits so the name is not completely wrong, but flipAllBits(flipAllBits(x)) != x (usually), while the name suggests it should be an involution.

As for the second question, there is nothing to determine. Two's complement is scheme by which you can interpret a bitvector - any bitvector. So it's really a choice you make; to interpret a given bitvector that way or some other way. In Java the "default" interpretation is two's complement (eg toString will print an int by interpreting it according to its two's complement meaning), but you don't have to go along with it, you can (with care) treat int as unsigned, or as an array of booleans, or several bitfields packed together, etc.

If you wanted to invert all the bits but made the common mistake to assume that the number of bits in an int is variable (and that you therefore needed to compute a mask that covers "all bits"), I have some great news for you, because inverting all bits is a lot easier:

return ~num;

If you were reading "invert all bits" in the context of two's complement, it would have the above meaning, so all bits, including those left of the highest set bit.

harold
  • 61,398
  • 6
  • 86
  • 164
  • You missed the meaning of the second question. The interest is in the detection of whether a sequence of bits is in the form of two's complement (Java int) or not (Java unsigned int), which one cannot without additional information. – Douglas Daseeco Feb 04 '17 at 01:42
  • @FauChristian I did not miss it, I dedicated a paragraph to it, which tells that not only you can't detect it, there is nothing to detect. – harold Feb 04 '17 at 13:10