You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

稳定版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 }
    }
}

实现思路说明

  1. mod=0的特殊处理:按要求将modulo=0等价为1<<128,而任何数对2^128取模的结果就是其128位无符号二进制表示,因此直接返回val as u128即可。
  2. 非负数场景:i128非负值的范围完全包含在u128的范围内,直接转换后取模不会触发溢出。
  3. 负数场景:
    • 避免直接对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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 08:20:31