How to fix a method that calculates powers in a binary number, but fails more often than not?

Viewed 72

I've been doodling around with this little piece of code that's supposed to calculate and print out which powers of 2 are summarized into a given number. It works fine with small odd numbers but gets lost when I want it to calculate even numbers or bigger ones.

I don't even know what I could try, the code looks alright, but I probably keep failing to notice.

System.out.println("Give a number");
    int gigaInt = si.nextInt();
    String  gigaBit = Integer.toBinaryString(gigaInt);
    String[] gigaBitArray = gigaBit.split("");

 System.out.println("Binary: " + gigaBit);

 List<Integer> powers = new ArrayList<Integer>();


 for(int counter = gigaBitArray.length-1; counter >= 0; counter--){
        if (gigaBitArray[counter].equals("1"))
            powers.add((int)Math.pow(2,counter));
        else if(gigaBitArray[counter].equals("0")){
            powers.add(0);

        }



    }


    System.out.println("Powers: " + powers);

So, obviously, the program is supposed to calculate the powers, and it does! in some cases... here, when given 9

Give a number 9 Binary: 1001 Powers: [8, 0, 0, 1]

But when I want it to calculate an even number, it always shows "1" as the only component, like this:

Give a number 8 Binary: 1000 Powers: [0, 0, 0, 1]

And whenever asked to deal with a big number, it just goes completely crazy:

Give a number 542 Binary: 1000011110 Powers: [0, 256, 128, 64, 32, 0, 0, 0, 0, 1]

I would be amazingly grateful for any kind of advice on this. It's probably just an infantile kind of mistake, so please, do point it out.

4 Answers

As per the comment by Dawood ibn Kareem, you are testing the low order bits first. If you want the high order powers listed first you will need an index variable and a power variable. Also, no need to check for "0". If it is not "1" then it must be "0".

int iIndex;
int iLength = gigaBitArray.length; 
int iPower = iLength - 1;

for ( iIndex = 0; iIndex < iLength; ++iIndex, --iPower )
{
    if ( gigaBitArray[iIndex].equals("1") )
    {
        powers.add((int)Math.pow(2, iPower));
    }
    else
    {
        powers.add(0);
    }
}

The problem with your code is the array index you are looking at. When you input the number 8, its binary representation is 1000. And when you split it into an array you get:

index: 0 1 2 3 value: 1 0 0 0

Because you are starting at the end of the list, index 0 will be processed last (and will be the same as 2^0).

All you need to do to fix this is to inverse the order of the elements you are looking at while keeping the same order of the for loop. Eg: Instead of:

gigaBitArray[counter]

It should be:

gigaBitArray[gigaBitArray.length -1 - counter]

In addition to both answers above you could also get rid of the if else by multiplying the 0s and 1s:

int len = gigaBitArray.length;
for (int i = 0; i < gigaBitArray.length; i++) {
     powers.add((int)Math.pow(2, --len)*Integer.parseInt(gigaBitArray[i]));
}

Here is one way to do it. Comments in code where not obvious. The idea here is that all information inside a computer is binary. Characters and numbers are printed out based on context. Since all information is in binary it can be shifted left or right to move the field of bits the same direction. This permits detecting a 1 or 0 bit without resorting to the overhead of String manipulation.

      for (int number : new int[] { 8, 10, 23, 11, 2, 4, 99
      }) {
         List<Integer> powers = new ArrayList<>();

         // starting bits to shift
         int shift = 0;
         // save number for printout
         int save = number;

         while (number > 0) {
            // ANDing the number with 1 will mask the
            // low order bit to a 1 or 0.
            // Then shift that bit "shift" number
            // of bits (first time thru is 0) and store
            // the power in p. Then increment # of bits
            // to shift.
            int p = (number & 1) << shift++;

            //add power to beginning of list.
            powers.add(0, p);

            // now shift the number right by 1 to position
            // for next bit.
            number >>= 1;

         }

         System.out.printf("%3d -> %s%n", save, powers);

      }

The above prints the following:

  8 -> [8, 0, 0, 0]
 10 -> [8, 0, 2, 0]
 23 -> [16, 0, 4, 2, 1]
 11 -> [8, 0, 2, 1]
  2 -> [2, 0]
  4 -> [4, 0, 0]
 99 -> [64, 32, 0, 0, 0, 2, 1]

Related