使用C#进行Int32数字的循环移位

6

成员们,

我想要做的是右移或左移一个 Int32 的数字(不是位!!)。

如果移动这个常数:

123456789

3提供

我应该获得

789123456

为了避免数字丢失,因为我们正在谈论圆形移位。 经过一些测试,我想出了这个可行的方法:

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;
        }
    }

我正在寻找的方法应该是一种算术解决方案,而不是将数字转换为字符串再进行旋转。 我还假设:
  • Int32值中没有0位数字,以防止任何数字的丢失。
  • Int32是非负数。
  • 正数旋转整数应向右移动,负数应向左移动。
我的算法已经完成了所有这些操作,我想知道是否有方法对其进行微调,是否有更好的算术解决方案来解决这个问题?

1
不是所有数字都可以这样旋转(考虑将1173741829向右旋转1个位置,90亿对于int来说太大了),那么它们呢?我们应该假设这种情况不会发生吗? - harold
@harold:是的,我假设这样的溢出不会发生,因为输入会更小 ;) - Dark Side
1
@dark 你的方法在 shift = 0 的情况下会抛出异常,同时尝试使用 uint.MaxValue 进行测试,它将给出一个无效的答案。 - Dzienny
1个回答

5

因为我无法抗拒“必须具有算术方法”这一挑战:D,所以对以下内容进行了调试:

    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;
    }

编辑 还有一些测试结果

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

哇,太酷了!我只是在尝试寻找一种解决方案,以处理负移位大于数字长度的情况,但是您的解决方案处理得非常好,并且不会产生不存在的0 :) - Dark Side
1
@Me.Name 看起来很不错,但是它不能处理 uint.MaxValue;你应该使用计算并返回 long 值类型以避免溢出问题。 - Dzienny
@Dzienny 感谢您的评论。uint.MaxValue 对于大多数移位操作确实会失败,因为结果无法适应 uint,但是 OP 表示输入将更小,并且返回值基于原始方法签名。尽管如此,对于那些想要没有警告的函数的人来说,这仍然是一个有效的观点:将所有 uint 更改为 ulong,包括返回值(但不更改输入值),确实可以解决问题。 - Me.Name
@DarkSide 很高兴你能用它 :) 负移位大于长度的秘密是在改变移位到(length-shift)之前对长度进行模运算。 - Me.Name

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接