PAYATHON 2026

Rust 中如何对超过 u128 范围的整数字符串计算模 4?

数据小许

直接逐位取模,无需解析完整整数

可以依次读取字符串中的十进制数字,每读入一位就更新余数。计算过程中只保存很小的中间值,即使输入的数值超过 u128 上限,也不会发生整数溢出。

下面的实现保留原来的函数签名,约定输入为非空、仅包含 ASCII 数字 0 到 9 的非负十进制整数字符串。

fn exponent_function(str: &str) -> u32 {
    assert!(!str.is_empty(), "input must not be empty");

    let mut remainder = 0_u32;

    for byte in str.bytes() {
        assert!(byte.is_ascii_digit(), "input must contain only digits");

        let digit = u32::from(byte - b'0');
        remainder = (remainder * 10 + digit) % 4;
    }

    remainder
}

使用示例:

assert_eq!(exponent_function("0"), 0);
assert_eq!(exponent_function("17"), 1);
assert_eq!(exponent_function("123456"), 0);
assert_eq!(exponent_function("00019"), 3);

let large_number = "9".repeat(1000);
assert_eq!(exponent_function(&large_number), 3);

为什么这个算法不会溢出?

假设已经读取的整数部分为 N,下一位数字为 d。追加这一位后,数值为 10 * N + d。

计算模 4 时,可以先把 N 换成它的余数:

(10 * N + d) % 4 = (10 * (N % 4) + d) % 4

因此,每一步只需要执行:

remainder = (remainder * 10 + digit) % 4

remainder 始终在 0..=3 内,digit 在 0..=9 内,取模前的中间值最大为 3 * 10 + 9 = 39。这个值与原始整数的大小无关,u32 足以保存。

原实现中的错误发生在 parse::<u128>() 阶段:完整整数尚未解析成功,程序就返回了错误,后面的 % 4 无法执行。

模 4 也可以只看最后两位

对于十进制整数,可以写成:

N = 100 * q + t

其中 t 是最后两位表示的数。因为 100 % 4 = 0,所以 N % 4 = t % 4。只有一位数字时,直接使用这一位即可。

如果输入已经保证合法,只读取最后两位就能计算结果。若还需要检查整个字符串是否包含非法字符,仍然必须遍历输入。上面的逐位算法同时完成验证和取余,时间复杂度为 O(n),额外空间复杂度为 O(1)。

输入格式和错误处理

示例允许前导零,但不接受空字符串、空白、正负号、小数点或非 ASCII 数字。它的输入规则比 parse::<u128>() 更窄,例如不接受带前导 + 的字符串。如果业务需要支持这种格式,应先明确规则,再单独处理符号。

示例在非法输入时使用 panic!,与原代码遇到解析错误就终止的处理方式一致。如果输入来自用户或外部系统,可以将返回类型改为 Result<u32, ...>,由调用方处理错误。

备注:内容仅供参考。