稳定版Rust中如何实现有符号数对无符号数的欧几里得取模?
稳定版Rust中实现标准欧几里得取模函数
mod_euclid 可以通过以下简洁且安全的方式实现要求的函数,全程避免溢出/下溢,且完全符合稳定版Rust的语法:
fn mod_euclid(val: i128, modulo: u128) -> u128 { // 处理mod=0的情况:按要求视为mod=1<<128,等价于返回val的128位无符号表示 if modulo == 0 { return val as u128; } if val >= 0 { // 非负数直接转u128取模,无溢出风险 val as u128 % modulo } else { // 计算负数的绝对值(避免i128::MIN取负溢出) let abs_val = u128::MAX - (val as u128) + 1; let rem = abs_val % modulo; // 欧几里得模规则:负数取模结果为 (mod - 余数),余数为0时直接返回0 if rem == 0 { 0 } else { modulo - rem } } }
实现思路说明
- mod=0的特殊处理:按要求将
modulo=0等价为1<<128,而任何数对2^128取模的结果就是其128位无符号二进制表示,因此直接返回val as u128即可。 - 非负数场景:
i128非负值的范围完全包含在u128的范围内,直接转换后取模不会触发溢出。 - 负数场景:
- 避免直接对
i128::MIN取负(会触发有符号溢出),通过补码特性计算绝对值:负数的补码val as u128等于2^128 - |val|,因此|val| = u128::MAX - (val as u128) + 1(u128::MAX即2^128-1)。 - 根据欧几里得模定义,负数
val的模结果为(modulo - (|val| % modulo)) % modulo,余数为0时直接返回0简化计算。
- 避免直接对
验证测试用例
将上述函数代入题目给出的测试用例,全部符合预期:
// mod=0场景(无panic/UB) mod_euclid(i128::MAX, 0); mod_euclid(0, 0); mod_euclid(i128::MIN, 0); // 常规场景验证 assert_eq!(mod_euclid(1, 10), 1); assert_eq!(mod_euclid(-1, 10), 9); assert_eq!(mod_euclid(11, 10), 1); assert_eq!(mod_euclid(-11, 10), 9); assert_eq!(mod_euclid(i128::MAX, 1), 0); assert_eq!(mod_euclid(0, 1), 0); assert_eq!(mod_euclid(i128::MIN, 1), 0); assert_eq!(mod_euclid(i128::MAX, u128::MAX), i128::MAX as u128); assert_eq!(mod_euclid(0, u128::MAX), 0); assert_eq!(mod_euclid(i128::MIN, u128::MAX), i128::MAX as u128);
内容的提问来源于stack exchange,提问作者TLW
相关产品推荐
相关产品推荐

