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

Posted

技术标签:

【中文标题】如何在 Rust 中将有符号整数添加到无符号整数,检查无符号溢出?【英文标题】:How do I add a signed integer to an unsigned integer in Rust, checking for unsigned overflow? 【发布时间】:2020-12-11 22:55:04 【问题描述】:

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

【问题讨论】:

【参考方案1】:

您可以使用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 &lt; 0?在这种情况下,它不会改变任何东西,因为对文字的逻辑操作算作constant expressions。

然而,虽然它允许用于字面量,但一般情况下是不允许的,因为特征方法不能是 const。因此,如果您有包装类型,例如Foo(isize) 则不允许在 const 上下文中说 foo &lt; Foo(0)。不过,可以说foo.is_negative() 因为Foo 仍然可以实现const fn is_negative()

是的,你仍然可以说 foo.0 &lt; 0,但这不是我想要说明的重点。

【讨论】:

jc,有理由更喜欢is_negative() 而不是&lt; 0 吗? 如果rhsisize::MIN,这不会溢出吗? 使用x &lt; 0 也很好,是的,它会溢出,我已经更新了使用wrapping_abs() 的答案。 @kmdreko 我为is_negative() vs &lt; 0添加了一些背景信息 @goose121 编号 isize::MIN 是 0b1000..000 而-(isize::MIN+1) 是 0b0111..1111 所以isize::MIN as usize == (isize::MIN+1) as usize + 1【参考方案2】:

一种方法是使用如下函数:

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

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

【讨论】:

以上是关于如何在 Rust 中将有符号整数添加到无符号整数,检查无符号溢出?的主要内容,如果未能解决你的问题,请参考以下文章

byte[] 到无符号 BigInteger?

C ++十六进制字符串到无符号整数[重复]

如何在python中将有符号整数转换为无符号整数

如何在 AVX2 中将 32 位无符号整数转换为 16 位无符号整数?

javascript中将整数添加千位符号

在 C# 中将 3 个字节转换为有符号整数