1

I have a problem. I am trying to find a combination of right shift operations. An example. I have an Input:

Let's say 30. I now what to find a and b, so that a >> b = mynumber (30).

That's my attempt:

private static Random rnd = new Random();
        private static int[] FindRightShift(int value)
        {
            int[] arr = new int[2];
            for (int i = 1; i < int.MaxValue; i++)
            {
                int b;
                if (int.TryParse((Math.Log(i / value) / Math.Log(2)).ToString(), out b))
                {
                    arr[0] = i;
                    arr[1] = b;
                    Console.WriteLine("{0} >> {1} = {2}", arr[0], arr[1], arr[0] >> arr[1]);
                    // return arr;
                }
            }
            return arr;
        }

This works but it takes ages since it is looping trough all combinations. How can I modify my function so it will return one random combination (of a and b) without looping through all?

Dark Side
  • 695
  • 2
  • 8
  • 18
  • 2
    Um, `a = mynumber, b = 0`? – Jon Skeet Jan 04 '15 at 17:57
  • Well, I meant a random combination where none of the two numbers, a and b, are 0. :P – Dark Side Jan 04 '15 at 18:05
  • 2
    Well pick a random number and shift the number *left* by that many bits... – Jon Skeet Jan 04 '15 at 18:05
  • a = mynumber << b. You need to ensure that no bits are lost, too. – usr Jan 04 '15 at 18:35
  • @usr a=mynumber << b has infinite solutions as Maths says, in programming "infinite" means "to the maximam integer number", so if you want all the solutions, you must iterate all the integers to int.MaxValue – niceman Jan 04 '15 at 22:21
  • if you need just one, choose any value for b(other than 0), then a= mynumber << b – niceman Jan 04 '15 at 22:22
  • @niceman : I am not sure if I understand you correctly, but from what I tried your solution seems not to work. Here is my code: http://pastebin.com/m8baE1e If I've missunderstood you feel free to tell me:) – Dark Side Jan 04 '15 at 22:48
  • @DarkSide your link says paste have been removed ! :) – niceman Jan 05 '15 at 15:36
  • Oh sorry:s Hopefully now you can see it : http://pastebin.com/AL3tnQ3Z – Dark Side Jan 06 '15 at 02:29
  • With a friends help we were able to come that far, but the problem is that the result is only sometimes correct, not always: http://puu.sh/e7N2T/ab94c95268.PNG Can you see why that happens?:) – Dark Side Jan 06 '15 at 02:30

2 Answers2

1

I sent you my updated version yesterday and as far as I tested it, all appears to work well. Any corrections are welcome.

The main concept is some math around what right shift really is: x / 2^y = number (where ^ means power)

        int maxPower = (int)Math.Log(int.MaxValue, 2); // 30 -> max power to not exceed int.MaxValue

        maxPower = (int)Math.Log(Math.Pow(2, maxPower) / number, 2); // prevent "NOTE1" > int.MaxValue

        for (int y = 0; y < maxPower; y++) // outputs all possible numbers; can be replaced with Random.Next(1, maxPower+1)
        {
            int sub = (int)Math.Pow(2, y);
            int x = number * sub; // NOTE1

            Console.WriteLine("{0} >> {1} = {2}", x, y, x >> y);
        }
Riuo
  • 413
  • 1
  • 3
  • 15
1

The main problem with the current setup, is that it doesn't check if the shift causes bits to go 'off'. Using a byte as example, the number 12 would be: 00001100

Meaning the maximum number of bytes that could be shift to the left is 4. Vice versa, using your example syntax of y, could also be a maximum of 4 (and x max 192 ) With ints and other signed variables, there's the added behaviour that when shifting a negative value, the first (sign) bit, is treated differently (see the last paragraph here. Shifting the postive number 1073741824 (1<<30) one position to the left, makes it negative (1<<31 == int.MinValue), but shifting that number back right, the negative sign is persisted, creating -1073741824. All that means is, that the check for max shifting is different between positive and negative values.

The method that comes to mind, is to determine the maximum bits that can be shift to the left to determine max 'y', do a random(1,y) to get the 'y' to use, and simply shift number y times to the left to get x.

private static void FindRightShift(int number)
{
    int maxshifts = 0, nr = number;
    Func<bool> check;
    if (number < 0) check = () => nr > (int.MinValue >> 1); else check = () => nr <  (1 << 30);
    while (check())
    {
        nr <<= 1;
        maxshifts++; //you could also opt to do a random break here
    }
    if (maxshifts ==0)
        throw new ArgumentException("Invalid number");
    int y = R.Next(1, maxshifts), x = number << y;
    //Debug.Assert((x >> y) == number);
    Console.WriteLine("{0} >> {1} = {2} (maxshifts: {3})", x, y, x >> y,  maxshifts);
}

The alternative would be to just keep trying a new random, until the reverse shift is true. Reusing your current code:

    int x, y;
    do
    {
        y = R.Next(1, 30); // random valid power       
        x = number << y;
    } while (x >> y != number);
    Console.WriteLine("{0} >> {1} = {2}", x, y, x >> y);
Me.Name
  • 12,259
  • 3
  • 31
  • 48