[英]How do I add a signed integer to an unsigned integer in Rust?
[英]Rust signed modulo unsigned -> unsigned
在(稳定的)Rust 中,是否有相对直接的方法来实现以下功能?
fn mod_euclid(val: i128, modulo: u128) -> u128;
注意类型,即“标准”欧氏模数(结果始终在[0, mod)
范围内),避免中间计算中的虚假溢出/下溢。 一些测试用例:
// don't-care, just no panic or UB.
// Mild preference for treating this as though it was mod=1<<128 instead of 0.
assert_dc!(mod_euclid(i128::MAX, 0));
assert_dc!(mod_euclid( 0, 0));
assert_dc!(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);
对于signed%signed->signed,或者unsigned%unsigned->unsigned,这个比较直接。 但是,我找不到一种不转换其中一个参数就计算 signed % unsigned -> unsigned 的好方法——正如最后一个示例所示,无论您选择哪个方向,这都可能溢出或下溢。
据我所知,标准库中没有这样的函数,但是自己写一个也不是很难:
fn mod_euclid(a: i128, b: u128) -> u128 {
if a >= 0 {
(a as u128) % b
} else {
let r = (!a as u128) % b;
b - r - 1
}
}
怎么运行的:
a
是非负的,那么它很简单——只需使用无符号余数运算符。!a
是非负的(因为符号位被翻转),并且在数值上等于-a - 1
。 这意味着r
等价于b - a - 1
模b
,因此b - r - 1
等价于a
模b
。 方便地, b - r - 1
在预期范围内0..b
。 也许更直接一点,尽可能使用rem_euclid
并返回if a >= 0 {a} else {u128::MAX + a}
else:
pub fn mod_euclid(a: i128, b: u128) -> u128 {
const UPPER: u128 = i128::MAX as u128;
match b {
1..=UPPER => a.rem_euclid(b as i128) as u128,
_ => a as u128 - (a < 0) as u128,
}
}
(解析器不喜欢我在比赛中的铸造,因此UPPER
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.