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

问题描述 投票:0回答:3

我想将

isize
添加到
usize
并包含边界检查,以便结果不会溢出
usize
的边界。这怎么办?

rust unsigned signed
3个回答
5
投票

您可以组合使用

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()
vs
rhs < 0
?在这种情况下,它不会改变任何东西,因为文字上的逻辑运算算作常量表达式

但是,虽然允许使用文字,但一般来说是不允许的,因为特征方法不能是

const
。因此,如果您有包装类型,例如
Foo(isize)
那么就不允许在 const 上下文中说
foo < Foo(0)
。不过,可以说
foo.is_negative()
,因为
Foo
仍然可以实现
const fn is_negative()

是的,你仍然可以说

foo.0 < 0
,但这超出了我想要表达的重点。


0
投票

实现此目的的一种方法是使用如下函数:

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,
        )
    }
}

这利用了这样一个事实:当从无符号数的角度来看,这样的加法应该仅在无符号数为负数时“溢出”(即表现出补码行为),并且如果在以下情况下不这样做数字为负数,这表示下溢。


0
投票

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_
    ,如上所示,返回一对,其中包含包装结果和指示是否发生溢出的布尔标志。
  • checked_
    返回
    Option
    ,溢出时为
    None
  • saturating_
    通过限制最大值和最小值来防止溢出(即
    MAX + 1 == MAX
    MIN - 1 == MIN
    )。
  • wrapping_
    没有解决您的用例 - 它只返回包装的结果,并不指示是否发生溢出。

在有符号整数上也有类似的方法,用于接受无符号参数并返回有符号结果的加法或减法,名为

*_add_unsigned
*_sub_unsigned

(注:改编自我的回答https://stackoverflow.com/a/73153135/6112457

© www.soinside.com 2019 - 2024. All rights reserved.