如何在Rust中将有符号整数添加到无符号整数,检查无符号溢出?

x4shl7ld  于 12个月前  发布在  其他
关注(0)|答案(3)|浏览(116)

我想将isize添加到usize中,并包括边界检查,以便结果不会溢出usize的边界。如何做到这一点?

wwodge7n

wwodge7n1#

您可以使用isize::is_negative()isize::wrapping_abs()usize::checked_add()usize::checked_sub()的组合。

const fn add(lhs: usize, rhs: isize) -> Option<usize> {
    if rhs.is_negative() {
        lhs.checked_sub(rhs.wrapping_abs() as usize)
    } else {
        lhs.checked_add(rhs as usize)
    }
}

字符串
为什么是isize::is_negative()rhs < 0?在这种情况下,它不会改变任何东西,因为对文字的逻辑操作算作常量表达式。
然而,虽然它被允许用于字面量,但通常是不允许的,因为traits方法不能是const。因此,如果你有一个 Package 类型,例如Foo(isize),那么在const上下文中就不允许说foo < Foo(0)。尽管如此,说foo.is_negative()是可能的,因为Foo仍然可以实现const fn is_negative()

  • 是的,你仍然可以说foo.0 < 0,但这不是我想表达的观点。*
du7egjpx

du7egjpx2#

Rustc 1.66+支持一些混合整数运算。请注意,这在mixed_integer_ops功能标志下以前不稳定。
有了这个,你可以做:

fn main() {
    let x: usize = foo();
    let y: isize = bar();
    let (res, flag): (usize, bool) = x.overflowing_add_signed(y); // returns a (usize, bool) pair to indicate if overflow occurred
    println!("{x} + {y} = {res}, overflowed? {flag}");
}

字符串
这些无符号整数的*_add_signed方法都接受一个有符号的参数,并返回一个无符号的结果。有几个变体,取决于你想如何具体处理溢出情况:

  • overflowing_,如上所示,返回一个pair,带有 Package 的结果和一个指示是否发生溢出的布尔标志。
  • checked_返回Option,在溢出时为None
  • saturating_通过箝位到最大值和最小值(即MAX + 1 == MAXMIN - 1 == MIN)来防止溢出。
  • wrapping_并没有解决你的用例--它只返回 Package 的结果,并不指示是否发生了溢出。

有符号整数也有类似的方法,用于加法或减法,它们接受无符号参数并返回有符号结果,名为*_add_unsigned*_sub_unsigned
(note:改编自我在https://stackoverflow.com/a/73153135/6112457的回答)

pgky5nke

pgky5nke3#

这样做的一种方法是使用如下函数:

fn signed_unsigned_add(x: usize, y: isize) -> usize {
    let (n, overflow) = x.overflowing_add(y as usize);
    if (y >= 0) ^ overflow {
        n
    } else {
        panic!(
            "signed + unsigned addition overflow: {} + {}",
            x,
            y,
        )
    }
}

字符串
这利用了这样一个事实,即当从无符号数的Angular 来看时,这样的加法应该只在无符号数为负数时“溢出”(即表现出二进制补码行为),并且如果当数字为负数时不这样做,则这表明下溢。

相关问题