旋转整数的数字

Rotate digits of an integer

提问人:Kittoes0124 提问时间:8/6/2023 最后编辑:Kittoes0124 更新时间:8/7/2023 访问量:132

问:

我正在尝试提出一个通用函数,该函数将给定数字的数字向左或向右旋转。在这一点上,我只能为左移制定一个实现:n

public static T RotateDigitsLeft<T>(this T value, int count) where T : IBinaryInteger<T> {
    var absoluteValue = T.Abs(value: value);
    var countAsT = T.CreateTruncating(value: count);
    var digitCount = absoluteValue.LogarithmBase10();
    var factor = BinaryIntegerConstants<T>.Ten.Exponentiate(exponent: (digitCount - countAsT));
    var endDigits = (absoluteValue / factor);
    var startDigits = (absoluteValue - (endDigits * factor));

    return T.CopySign(sign: value, value: ((startDigits * BinaryIntegerConstants<T>.Ten.Exponentiate(exponent: countAsT)) + endDigits));
}
  • 是否有可能以适用于负值的方式更改它?count
  • 旋转的子集会导致无效值,具体取决于 的大小 ;有没有一种体面的方法可以通用地检查这些,以便人们可以投掷?T
  • 是否可以更改功能以支持右旋转?

注意:继续使用算术的答案将是首选,因为我发现它们更有趣。

例子:

  • 54321 -> 43215(向左旋转 1 次,向右旋转 4 次)
  • 54321 -> 32154(向左旋转 2 次,向右旋转 3 次)
  • 54321 -> 21543(向左旋转 3 次,向右旋转 2 次)
  • 54321 -> 15432(向右旋转 1,向左旋转 4)
  • 54321 -> 21543(向右旋转 2 次,向左旋转 3 次)
  • 54321 -> 32154(向右旋转 3 次,向左旋转 2 次)
  • 1123456789 -> 1234567891(向左旋转 1)
  • 1123456789 -> EXCEPTION(向右旋转 1)
C# 数学 旋转 数字

评论

1赞 Axel Kemper 8/6/2023
你看过这个相关的帖子吗?
1赞 Kittoes0124 8/6/2023
@AxelKemper 对不起,这是关于旋转的;我们的目标是轮换数字
0赞 Luatic 8/6/2023
@Kittoes0124位实际上只是以 2 位为基数。逻辑是相同的,只是位允许您利用硬件位。
0赞 Kittoes0124 8/6/2023
@Luatic太好了,现在画剩下的猫头鹰。
1赞 Luatic 8/6/2023
@Kittoes0124现在使用它,但首先必须安装 mono,因为我通常不做 C# :)

答:

1赞 Dmitry Bychenko 8/6/2023 #1

我建议转换整数以旋转它,然后再转换回整数:stringParse

public static T RotateDigitsLeft<T>(this T value, int count) 
  where T : IBinaryInteger<T> {
  
  string text = value.ToString().TrimStart('-');

  count = (count % text.Length + text.Length) % text.Length;

  char[] digits = new char[text.Length];

  for (int i = 0; i < digits.Length; ++i)
    digits[i] = text[(i + count) % digits.Length];

  string result = new string(digits);

  if (value < T.Zero)
    result = "-" + result;

  return T.Parse(result, CultureInfo.InvariantCulture);
}

和之间的唯一区别在于计算,即RotateDigitsRightRotateDigitsLeftcount

public static T RotateDigitsRight<T>(T value, int count) 
  where T : IBinaryInteger<T> {

  string text = value.ToString().TrimStart('-');

  // The only difference is here  
  count = text.Length - (count % text.Length + text.Length) % text.Length;

  char[] digits = new char[text.Length];

  for (int i = 0; i < digits.Length; ++i)
    digits[i] = text[(i + count) % digits.Length];

  string result = new string(digits);

  if (value < T.Zero)
    result = "-" + result;

  return T.Parse(result, CultureInfo.InvariantCulture);
}

小提琴

请注意,旋转的设计可能会引发异常,例如,如果我们旋转例如 通过将得到或超出范围。byte25515525250..255

另一个问题(我已经避免了)是负数:请注意,这可能超出范围,例如 不能计算为:Abs(value)Abs(int.MinValue)int

  // -1474836482
  // even if Math.Abs(int.MinValue) not a valid int
  int result = RotateDigitsLeft(int.MinValue, 1);
1赞 Thomas 8/6/2023 #2

我仍在学习 C#,所以我不确定你的 ,但我会走字符串的方式:IBinaryInteger<T>

// careful with zeroes, they may end up at the start.
static int RotateLeft(int value, int count)
{
    string sign = value < 0 ? "-" : "";
    string digits = value.ToString().TrimStart('-');
    // rotation may be > 1 full rotation,
    // let's bring it in the range < 1 full rotation
    count %= digits.Length;

    // count was a multiple of a full rotation, 
    // nothing to rotate here.
    if (count == 0)
        return value;
    
    // negative count == RotateRight
    // let's turn this into the equivalent positive value
    if (count < 0)
        count += digits.Length;
    
    return int.Parse(
        sign + 
        digits.Substring(count, digits.Length - count) + 
        digits.Substring(0, count)
    );
}

static int RotateRight(int value, int count) {
    return RotateLeft(value, -count);
}

评论

0赞 Dmitry Bychenko 8/6/2023
请注意:如果出现整数溢出Math.Abs(value)value == int.MinValue
0赞 Kittoes0124 8/6/2023
这里;这真是整洁的东西!
1赞 Dmitry Bychenko 8/6/2023
如果你想支持任意(例如neagtive),你可以使用模算术,加法是不够的,例如for和countcount = (count % digits.Length + digits.Length) % digits.Length;digits.Lengthcount = -101digits.Length = 5
0赞 Thomas 8/7/2023
@DmitryBychenko之后,我在第 3 行中涵盖了该部分,则在 的范围内,因此如果计数为负数,则添加就足够了。我不知道是两个模还是分支更差/更好,但这两种方法最终都会导致相同的结果。count %= digits.Length;count-Length < count < LengthLength
2赞 Luatic 8/6/2023 #3

对 n 位数字进行右旋相当于对 m 位数字进行 m - n 位的左旋:

例如,要123456向右旋转 2 次,我们将向左旋转 6 - 2 = 4:

123456 → 612345 → 561234 → 456123 → 345612

这相当于向右旋转两次:

123456 → 234561 → 345612

因此,我们只需要进行简单的更改来支持负旋转值:

if (count < 0) countAsT += digitCount;

在计算之后,在执行其余的旋转之前。我不确定这在类型上是否正确;我找不到返回类型的文档。不过,这将是明智的;如果不是,你就必须施放它。digitCountLogarithmBase10int

我根据德米特里的小提琴创建了一个最小的小提琴供您测试。

评论

0赞 Kittoes0124 8/6/2023
如果更容易,请随意写成 or ;可以从那里执行到通用接口的机械转换。Tintuint
0赞 Luatic 8/6/2023
@Kittoes0124它现在正在工作。我只需要使用,因为是一个.countAsTdigitCountT