6

Members,

What I am trying to do is to right or left shift the digits of an Int32(not the bits!!).

So if shift the constant:

123456789

by 3

I should get

789123456

So no digits get lost, because we talk about a circular shift. After a bit of testing I've come up with this method, which works:

static uint[] Pow10 = new uint[] { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, uint.MaxValue };
    static uint RotateShift10(uint value, int shift)
    {
        int r = (int)Math.Floor(Math.Log10(value) + 1);
        while (r < shift)
            shift = shift - r;
        if (shift < 0) shift = 9 + shift;
        uint x = value / Pow10[shift];
        uint i = 0;
        while (true)
        {
            if (x < Pow10[i])
                return x + (value % Pow10[shift]) * Pow10[i];
            i += 1;
        }
    }

The way I am looking for should be an arithmetic solution, not a string conversion and then the rotation. I also assume that:

  • The Int32 value has no 0-digits in it, to prevent any loss of digits.
  • The Int32 is a non-negative number
  • A positive Rotation integer should shift to the right, and negative one to the left.

My algorithm already does all of that, and I like to know if there are way to tweak it a bit, if there is a better arithmetic solution to the problem?

Jake
  • 328
  • 2
  • 14
Dark Side
  • 695
  • 2
  • 8
  • 18
  • 1
    Not all numbers can be rotated that way (consider 1173741829 rotated right by 1 position, 9 billion is way too large for an int), what about them? Should we assume that won't happen? – harold Jul 01 '15 at 17:59
  • @harold : yes, I assume such an overflow wont happen, since the input will be smaller ;) – Dark Side Jul 01 '15 at 18:02
  • 1
    @dark Your method throws for `shift` = 0, also try it with uint.MaxValue, it will give an invalid answer. – Dzienny Jul 01 '15 at 19:05

1 Answers1

5

Because I just can't resist a 'has to have an arithmetic approach' challenge :D , fiddled around with the following:

    static uint RotateShift(uint value, int shift)
    {
        int len = (int)Math.Log10(value) + 1;
        shift %= len;
        if (shift < 0) shift += len;            
        uint pow = (uint)Math.Pow(10, shift);
        return (value % pow) * (uint)Math.Pow(10, len - shift) + value / pow;
    }

edit Also some test results

foreach(var val in new uint[]{123456789, 12345678})
   foreach (var shift in new[] { 3, -3, 1, -1, 11, -11, 18 })
   {
      Console.WriteLine("Value {0} Shift {1} -> {2}", val, shift, RotateShift(val, shift));
   }

Value 123456789 Shift 3 -> 789123456
Value 123456789 Shift -3 -> 456789123
Value 123456789 Shift 1 -> 912345678
Value 123456789 Shift -1 -> 234567891
Value 123456789 Shift 11 -> 891234567
Value 123456789 Shift -11 -> 345678912
Value 123456789 Shift 18 -> 123456789
Value 12345678 Shift 3 -> 67812345
Value 12345678 Shift -3 -> 45678123
Value 12345678 Shift 1 -> 81234567
Value 12345678 Shift -1 -> 23456781
Value 12345678 Shift 11 -> 67812345
Value 12345678 Shift -11 -> 45678123
Value 12345678 Shift 18 -> 78123456
Me.Name
  • 12,259
  • 3
  • 31
  • 48
  • Whow, thats cool! I was just trying to find a solution how to handle bigger shifts than the length of the number when the shift is negative, but your solution handles this quiet nciely and doesn't produce 0's where are none :) – Dark Side Jul 01 '15 at 18:58
  • 1
    @Me.Name It looks impressive, unfortunately it doesn't work for the `uint.MaxValue`; you should compute with and return a `long` value type to avoid the overflow problem. – Dzienny Jul 01 '15 at 20:15
  • @Dzienny Thanks for your comment. uint.MaxValue would indeed fail for most shifts since the result would not fit inside a uint, however the OP stated that the input will be smaller and the return value is based on the original method signature. Still, it's a valid point for those that would want a function without caveats: changing all uints to ulongs, including the return value (but not changing the input value), will indeed do the trick. – Me.Name Jul 01 '15 at 20:35
  • @DarkSide Glad you could use it :) The secret of the negative shift greater than the length is to do the modulo on lenght before altering the shift to (length-shift) – Me.Name Jul 01 '15 at 20:38