Faster way of adding negative signed to unsigned

286 views Asked by At

Assuming I have a: usize and a negative b:isize how do I achieve the following semantics - reduce a by absolute value of b in fastest manner possible?

I already thought of a - (b.abs() as usize), but I'm wondering if there is a faster way. Something with bit manipulation, perhaps?

2

There are 2 answers

3
DK. On BEST ANSWER

Why do you assume this is slow? If that code is put in a function and compiled, on x86-64 linux, it generates the following:

_ZN6simple20h0f921f89f1d823aeeaaE:
    mov rax, rsi
    neg rax
    cmovl rax, rsi
    sub rdi, rax
    mov rax, rdi
    ret

That's assuming it doesn't get inlined... which I had to work at for a few minutes to prevent the optimiser from doing in order to get the above.

That's not to say it definitely couldn't be done faster, but I'm unconvinced it could be done faster by much.

0
Francis Gagné On

If b is guaranteed to be negative, then you can just do a + b.

In Rust, we must first cast one of the operands to the same type as the other one, then we must use wrapping_add instead of simply using operator + as debug builds panic on overflow (an overflow occurs when using + on usize because negative numbers become very large positive numbers after the cast).

fn main() {
    let a: usize = 5;
    let b: isize = -2;
    let c: usize = a.wrapping_add(b as usize);
    println!("{}", c); // prints 3
}

With optimizations, wrapping_add compiles to a single add instruction.