Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to subtract an isize from a usize?

I've got a usize that does hit very large values. I also apply a delta to it that I receive in the form of an isize. What's the best way to apply the delta without losing any precision?

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;
    }
}
like image 201
Ripread Avatar asked Dec 06 '19 07:12

Ripread


People also ask

What is the size of Usize?

Conservatively assume that usize may be as narrow as 8 bits. Liberally assume that usize is at least 32 bits wide (as it is on all current officially supported platforms). Let me know if I missed any other corners of the standard library which make assumptions (identical to one of these or not).

What is Usize type?

Introduction to Rust usize. It is a primitive type of rust, which is based on pointer like C programming language. If we have a type that does not have a definite size, we call those primitive types as 'usize' in rust or dynamically sized types in rust. It is representing as the pointer sized unsigned type in rust.

What is Usize used for in rust?

Use usize and isize when it's related to memory size -- the size of an object, or indexing a vector, for instance. It will be a 32-bit number on 32-bit platforms, as that's the limit of memory they can address, and likewise for 64-bit. Use u32 and i32 when you just want numbers.


1 Answers

There are two ways:

  • either you keep all your value in range of isize (the choice of rust std for example)
  • or you only work with usize and handle sign yourself (clearly my preferred choice).

But the implementation is up to you; for example, you could have a bool that tells you if the offset is a difference or an addition, or use an enum:

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

This is not ugly at all; you just have to use some trait to hide the logic and then you just have to use it.

like image 123
Stargateur Avatar answered Sep 29 '22 20:09

Stargateur