7

I am trying to write a bitwise calculator in java, something that you could input an expression such as ~101 and it would give back 10 however when i run this code

import java.util.Scanner;

public class Test
{
    public static void main(String[] args)
    {
        Integer a = Integer.valueOf("101", 2);
        System.out.println(Integer.toString(~a,2));
    }
}

it outputs -110 why?

madth3
  • 7,275
  • 12
  • 50
  • 74
Josh Sobel
  • 1,268
  • 3
  • 14
  • 27

5 Answers5

11

You are assuming that 101 is three bits long. Java doesn't support variable length bit operations, it operates on a whole int of bits, so ~ will be the not of a 32 bit long "101".

--- Edited after being asked "How can I fix this?" ---

That's a really good question, but the answer is a mix of "you can't" and "you can achieve the same thing by different means".

You can't fix the ~ operator, as it does what it does. It would sort of be like asking to fix + to only add the 1's place. Just not going to happen.

You can achieve the desired operation, but you need a bit more "stuff" to get it going. First you must have something (another int) that specifies the bits of interest. This is typically called a bit mask.

 int mask = 0x00000007; // just the last 3 bits.

 int masked_inverse = (~value) & mask;

Note that what we did was really invert 32 bits, then zeroed out 29 of those bits; because, they were set to zero in the mask, which means "we don't care about them". This can also be imagined as leveraging the & operator such that we say "if set and we care about it, set it".

Now you will still have 32 bits, but only the lower 3 will be inverted. If you want a 3 bit data structure, then that's a different story. Java (and most languages) just don't support such things directly. So, you might be tempted to add another type to Java to support that. Java adds types via a class mechanism, but the built-in types are not changeable. This means you could write a class to represent a 3 bit data structure, but it will have to handle ints internally as 32 bit fields.

Fortunately for you, someone has already done this. It is part of the standard Java library, and is called a BitSet.

BitSet threeBits = new BitSet(3);
threeBits.set(2);  // set bit index 2
threeBits.set(0);  // set bit index 0
threeBits.flip(0,3);

However, such bit manipulations have a different feel to them due to the constraints of the Class / Object system in Java, which follows from defining classes as the only way to add new types in Java.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • @JoshSobel I updated the answer. Some really short questions require long explanations, as they are just lucky enough to open up doors of new understanding. Good luck on your endeavor. – Edwin Buck Mar 22 '13 at 17:12
  • but how would i dynamically adjust the mask to fit the given number – Josh Sobel Mar 22 '13 at 21:41
  • @JoshSobel If you are dynamically updating the mask, then you can't compare numbers that don't have the same fixed _number_ of used bits; but, to answer your question, with the int mask solution, just reset the mask variable to the new mask. With the BitSet solution, create a new bit set, and then set the same bits in it that were set in the other bit set. I can't imagine where either solution would be the right answer to any particular problem, unless resetting the mask also required you to reset the value. – Edwin Buck Mar 22 '13 at 22:22
  • Josh, don't you know the number of bits in the input number because of the length of the input string? I would think that would solve your problem. Integer provides a way to produce a binary string from an int that is only as long as it needs to be (so int x = 3 would give you binary string of 11, length of two.) –  Jul 01 '13 at 04:09
2

If a = ...0000101 (bin) = 5 (dec)

~a = ~...0000101(bin) = ...1111010(bin) 

and Java uses "Two's complement" form to represent negative numbers so

~a = -6 (dec)

Now difference between Integer.toBinaryString(number) and Integer.toString(number, 2) for negative number is that

  • toBinaryString returns String in "Two's complement" form but
  • toString(number, 2) calculates binary form as if number was positive and add "minus" mark if argument was negative.

So toString(number, 2) for ~a = -6 will

  1. calculate binary value for 6 -> 0000110,
  2. trim leading zeros -> 110,
  3. add minus mark -> -110.
Pshemo
  • 122,468
  • 25
  • 185
  • 269
0

The toString() method interprets its argument as a signed value.

To demonstrate binary operations its better to use Integer.toBinaryString(). It interprets its argument as unsigned, so that ~101 is output as 11111111111111111111111111111010.

If you want fewer bits of output you can mask the result with &.

Joni
  • 108,737
  • 14
  • 143
  • 193
0

101 in integer is actually represented as 00000000000000000000000000000101 negate this and you get 11111111111111111111111111111010 - this is -6.

assylias
  • 321,522
  • 82
  • 660
  • 783
enigma
  • 89
  • 6
  • I think OP is wondering why if binary representation of ~a is `...111111010`, `toString(~a,2)` prints `-110`? – Pshemo Mar 22 '13 at 17:05
0

Just to elaborate on Edwin's answer a bit - if you're looking to create a variable length mask to develop the bits of interest, you might want some helper functions:

/**
 * Negate a number, specifying the bits of interest.
 * 
 * Negating 52 with an interest of 6 would result in 11 (from 110100 to 001011).
 * Negating 0 with an interest of 32 would result in -1 (equivalent to ~0).
 * 
 * @param number the number to negate.
 * @param bitsOfInterest the bits we're interested in limiting ourself to (32 maximum).
 * @return the negated number.
 */
public int negate(int number, int bitsOfInterest) {
    int negated = ~number;
    int mask = ~0 >>> (32 - bitsOfInterest);
    logger.info("Mask for negation is [" + Integer.toBinaryString(mask) + "]");
    return negated & mask;
}

/**
 * Negate a number, assuming we're interesting in negation of all 31 bits (exluding the sign).
 * 
 * Negating 32 in this case would result in ({@link Integer#MAX_VALUE} - 32).
 * 
 * @param number the number to negate.
 * @return the negated number.
 */
public int negate(int number) {
    return negate(number, 31);
}
David Levy
  • 587
  • 1
  • 6
  • 9