如何从usize中减去isize?

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

我有一个usize确实击中了非常大的值。我还以isize的形式对其应用了增量。在不损失任何精度的情况下应用增量的最佳方法是什么?

fn main() {
    let mut big_indexer: usize = 4295032832; // 2^32 + 2^16
    let delta: isize = -65792; // 2^16 + 2^8

    let big_indexer = (big_indexer as isize) + delta // Can't do this b/c overflow
    let big_indexer = big_indexer + (delta as usize) // Can't do this b/c lose negative number

    // This is ugly
    if delta < 0 {
        let big_indexer -= delta.abs() as usize;
    } else {
        let big_indexer += delta.abs() as usize;
    }
}
types rust type-conversion primitive
3个回答
2
投票

有两种方法:

  • 要么将所有值都保持在isize范围内(例如选择锈std
  • 或您仅使用usize并亲自签署(显然是我的首选)。

但是实施取决于您;例如,您可以使用bool来告诉您偏移量是差值还是加法,或者使用枚举:

fn foo(n: usize, offset: usize, sub: bool) -> Option<usize> {
    (if sub {
        usize::checked_sub
    } else {
        usize::checked_add
    })(n, offset)
}

enum OffSet {
    Neg(usize),
    Pos(usize),
}

fn bar(n: usize, offset: OffSet) -> Option<usize> {
    match offset {
        OffSet::Pos(offset) => n.checked_add(offset),
        OffSet::Neg(offset) => n.checked_sub(offset),
    }
}

fn main() {
    let n = 4295032832; // 2^32 + 2^16
    let offset = 65792; // 2^16 + 2^8
    let sub = true;
    assert_eq!(Some(n - offset), foo(n, offset, sub));
    assert_eq!(Some(n - offset), bar(n, OffSet::Neg(offset)));
}

这一点都不难看;您只需要使用一些特征来隐藏逻辑,然后就可以使用它。


0
投票

取决于您的机器,usize is either 32 bit or 64 bitisize相同,除了第一位是符号位。因此,不知道索引器的上限,安全的方法是将两个值都转换为i128

let big_indexer = (big_indexer as i128) + delta as i128

0
投票

Stargateur's answer通常是很好的建议,但让我们假设您不能只是重写API以消除isize,也不能限制usize的范围。在这种情况下,您可以将delta强制转换为usize并显式使用换行算法:

// DON'T COPY THIS LINE unless you read the caveat below first
big_indexer = big_indexer.wrapping_add(delta as usize);

这适用于问题中的示例,但有一个“大”警告:如果deltabig_indexer均为正,并且它们的总和将溢出,则会自动换行。如果您保证使用的数字在范围内,那很好。如果需要将isize添加到usize 检测溢出,则返回“丑陋的” if表达式。

fn add_offset(big_indexer: usize, delta: isize) -> Option<usize> {
    if delta < 0 {
        big_indexer.checked_sub(delta.wrapping_abs() as usize)
    } else {
        big_indexer.checked_add(delta as usize)
    }
}

如果您经常使用换行算法,则可能需要使用std::num::Wrapping结构以使其更加方便。

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