通用整数数字旋转函数优化:支持正负偏移、右旋转及溢出检查
通用整数数字旋转函数的实现问题
背景
我正尝试实现一个通用函数,可将给定整数的数字向左或向右旋转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位)
- 1123456789 → 1234567891(左旋转1位)
- 1123456789 → EXCEPTION(右旋转1位)
解决方案
1. 支持count为负值的场景
先对count做归一化处理:基于数字总位数,将超出位数的旋转次数简化(比如5位数左旋转6位等价于左旋转1位);若count为负,直接转换为对应的正向旋转次数(比如右旋转1位等价于左旋转总位数-1位)。
核心修改逻辑:
var digitCount = absoluteValue.LogarithmBase10(); int intDigitCount = int.CreateTruncating(digitCount); // 简化旋转次数,负数转为正向等效值 count = count % intDigitCount; if (count < 0) count += intDigitCount; var countAsT = T.CreateTruncating(count);
2. 泛型溢出检查与异常抛出
利用IBinaryInteger<T>提供的TryMultiply、TryAdd、TryDivide等方法,在算术操作前判断是否会超出T的范围,若操作失败则抛出OverflowException。
以核心计算步骤为例:
// 计算10的幂时检查溢出 var tenPower = BinaryIntegerConstants<T>.Ten.Exponentiate(countAsT); // 乘法操作检查溢出 if (!T.TryMultiply(startDigits, tenPower, out var multiplied)) { throw new OverflowException($"旋转后的值超出类型 {typeof(T)} 的范围"); } // 加法操作检查溢出 if (!T.TryAdd(multiplied, endDigits, out var resultValue)) { throw new OverflowException($"旋转后的值超出类型 {typeof(T)} 的范围"); }
3. 支持右旋转
右旋转的算术实现逻辑:将最后k位移到数字最前方,步骤如下:
- 计算数字总位数
digitCount - 取最后k位:
endDigits = absoluteValue % (10^k) - 取剩余前半部分:
startDigits = absoluteValue / (10^k) - 结果为:
endDigits * 10^(digitCount - k) + startDigits
可以直接复用归一化后的count逻辑,将右旋转转为负count的左旋转,或单独实现右旋转函数:
public static T RotateDigitsRight<T>(this T value, int count) where T : IBinaryInteger<T> { return value.RotateDigits(-count); }
完整整合实现
public static T RotateDigits<T>(this T value, int count) where T : IBinaryInteger<T> { if (value == T.Zero) return value; var absoluteValue = T.Abs(value); var digitCount = absoluteValue.LogarithmBase10(); int intDigitCount = int.CreateTruncating(digitCount); if (intDigitCount == 0) return value; // 归一化旋转次数 count = count % intDigitCount; if (count < 0) count += intDigitCount; if (count == 0) return value; var countAsT = T.CreateTruncating(count); T resultValue; // 左旋转核心逻辑 var leftFactor = BinaryIntegerConstants<T>.Ten.Exponentiate(digitCount - countAsT); if (!T.TryDivide(absoluteValue, leftFactor, out var endDigits)) { throw new OverflowException($"操作超出类型 {typeof(T)} 的范围"); } var startDigits = absoluteValue - endDigits * leftFactor; var tenPowerLeft = BinaryIntegerConstants<T>.Ten.Exponentiate(countAsT); if (!T.TryMultiply(startDigits, tenPowerLeft, out var multipliedLeft)) { throw new OverflowException($"旋转后的值超出类型 {typeof(T)} 的范围"); } if (!T.TryAdd(multipliedLeft, endDigits, out resultValue)) { throw new OverflowException($"旋转后的值超出类型 {typeof(T)} 的范围"); } return T.CopySign(resultValue, value); } // 单独的右旋转入口 public static T RotateDigitsRight<T>(this T value, int count) where T : IBinaryInteger<T> { return value.RotateDigits(-count); }
补充说明:
- 需确保
LogarithmBase10方法能正确计算数字位数,对0做特殊处理 - 所有算术操作均通过
TryXXX方法做溢出校验,保证类型安全性 - 旋转次数归一化避免了无效计算,提升了函数效率
内容的提问来源于stack exchange,提问作者Kittoes0124
相关产品推荐
相关产品推荐

