6

I don't know to search or google it so I ask it here. I have an array of integers with fixed size and exactly with this logic.

sample [1,2,4,8,16,32]

Now I am given a number for example 26. And I shall find the numbers whose sum will make this number, in this case is [2,8,16]

for a number of 20 it will be [4,16]

for 40 it is [8,32]

and for 63 it is all of these numbers [1,2,4,8,16,32]

What is the proper algorithm for that?

I know strictly that there is always this continuation that the number is double of the previous value. as well as only the numbers from the given array will sum up to the given number and each number will be used only for once or none

If it will be in C# method that takes array of ints and an int value and returns the array of ints that contains the ints that sum up this number from the given array will be preferred.

Thank you

7
  • What if there are more then one possible combination? Or isn't the example on purppose and you are looking for the byte "version" of a number? Commented Aug 2, 2017 at 13:33
  • You can tell the indices that you need to add by the 1 bits in your number Commented Aug 2, 2017 at 13:33
  • 1
    @MightyBadaboom the given continuations restricts the value to have only and only one combination and not more Commented Aug 2, 2017 at 13:34
  • What you really have is a 2's exponential [1,2,4,8,16,32] = [2^0 ... 2^5] Commented Aug 2, 2017 at 13:35
  • @NeilLocketz I dont understand what you mean. Can you explain it better? Commented Aug 2, 2017 at 13:35

4 Answers 4

4

As you can see, the number are base-2, which means you can easily use shift.

You could try this:

private IEnumerable<int> FindBits(int value)
{
    // check for bits.
    for (int i = 0; i < 32; i++)
    {
        // shift 1 by i
        var bitVal = 1 << i;   // you could use (int)Math.Pow(2, i); instead
        // check if the value contains that bit.
        if ((value & bitVal) == bitVal)
            // yep, it did.
            yield return bitVal;
    }
}

This method will check what bits are set and return them as an ienumerable. (which can be converted to an array of list)


Usage:

// find the bits.
var res = FindBits(40).ToArray();

// format it using the string.join
var str = $"[{string.Join(",", res)}]";

// present the results
Console.WriteLine(str);

Results in [8,32]


Extra info:

                          counter
00000001 =   1     = 1 << 0
00000010 =   2     = 1 << 1 
00000100 =   4     = 1 << 2
00001000 =   8     = 1 << 3
00010000 =  16     = 1 << 4
00100000 =  32     = 1 << 5
01000000 =  64     = 1 << 6
10000000 = 128     = 1 << 7

Instead of writing all combinations you make a for loop which does the counter.


Some extra non-sense:

If you like lambda's, you could replace the FindBits with this:

private Func<int, IEnumerable<int>> FindBits = (int value) => Enumerable
    .Range(0, 31)
    .Select(i => 2 << i).Where(i => (value & i) == i);

But it's better to keep it simpel/readable.

Sign up to request clarification or add additional context in comments.

1 Comment

I'm still writing some extra info. You might read it for knowledge ;-)
2

First you should notice that

 ( 1    2    4    8    16 ... ) = (2^0  2^1  2^2  2^3  2^4 ... )

And that this is the same as finding a binary encoding for a decimal number. What you are looking for is an algorithm to transform a decimal or base 10 number to a binary or base 2 number.

The algorithm is pretty simple:

public List<int> dec_to_bin(int num)
{
    List<int> return_list = new List<int>();
    int index = 0; 
    int remainder = num;
    int bit = 0;

    while (remainder > 0)
    {
        bit = remainder % 2;

        if (bit == 1 )
        {
            return_list.Add((int)Math.Pow(2, index));
        }

        remainder = remainder / 2; 
        index = index + 1;
   }

   return return_list;
}

There is a better way however that just uses the underlying encoding of the number which is already binary.

public List<int> dec_to_bin(int num)
{
    List<int> return_list = new List<int>();
    int value = 1; 

    while( value < num )
    {
         if( (value & num) == value )
         {
             return_list.Add(value);
         }
         value = value * 2; 
    }
    return return_list;
}

Comments

1

Another way to state your requirement is "What are the unique powers of 2 that sum to a given integer?" Since computers work with powers of 2 natively, there are built-in goodies in most languages to do this very succinctly.

As a bonus, you can use existing .Net types and methods to eliminate the need to write your own loops.

Here's one approach:

IEnumerable<int> GetCompositePowersOf2(int input) =>
    //convert to enumerable of bools, one for each bit in the 
    //input value (true=1, false=0)
    new BitArray(new[] { input }).Cast<bool>()
    // get power of 2 corresponding to the position in the enumerable 
    // for each true value, gets 0 for false values.
    .Select((isOne, pos) => isOne ? (1 << pos) : 0)
    //filter out the 0 values
    .Where(pow => pow > 0);

Comments

0

I don't quite get the " takes array of ints " part, since this creation of sums only works with numbers that are the power of 2.

    private int[] count (int num)
    {

        int factor = 0;
        List<int> facts = new List<int>();
        while (num > 0)
        {
            int counter = 0;
            int div = num;
            int remainder = 0;
            while (remainder == 0)
            {
                remainder = div % 2;
                div = div / 2;
                counter++;
            }
            factor = 1;
            for (int i = 1; i < counter; i++) 
                factor *= 2;
            num = num - factor;
            facts.Add(factor);
        }

        return (facts.ToArray());
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.