提问人:Kittoes0124 提问时间:8/6/2023 最后编辑:Kittoes0124 更新时间:8/7/2023 访问量:132
旋转整数的数字
Rotate digits of an integer
问:
我正在尝试提出一个通用函数,该函数将给定数字的数字向左或向右旋转。在这一点上,我只能为左移制定一个实现: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)
答:
1赞
Dmitry Bychenko
8/6/2023
#1
我建议转换整数以旋转它,然后再转换回整数:string
Parse
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);
}
和之间的唯一区别在于计算,即RotateDigitsRight
RotateDigitsLeft
count
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);
}
请注意,旋转的设计可能会引发异常,例如,如果我们旋转例如 通过将得到或超出范围。byte
255
1
552
525
0..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和count
count = (count % digits.Length + digits.Length) % digits.Length;
digits.Length
count = -101
digits.Length = 5
0赞
Thomas
8/7/2023
@DmitryBychenko之后,我在第 3 行中涵盖了该部分,则在 的范围内,因此如果计数为负数,则添加就足够了。我不知道是两个模还是分支更差/更好,但这两种方法最终都会导致相同的结果。count %= digits.Length;
count
-Length < count < Length
Length
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;
在计算之后,在执行其余的旋转之前。我不确定这在类型上是否正确;我找不到返回类型的文档。不过,这将是明智的;如果不是,你就必须施放它。digitCount
LogarithmBase10
int
我根据德米特里的小提琴创建了一个最小的小提琴供您测试。
评论
0赞
Kittoes0124
8/6/2023
如果更容易,请随意写成 or ;可以从那里执行到通用接口的机械转换。T
int
uint
0赞
Luatic
8/6/2023
@Kittoes0124它现在正在工作。我只需要使用,因为是一个.countAsT
digitCount
T
评论