Search code examples
rustbit-shift

How do I represent an i64 in the u64 domain?


What is the rusticle way to to represent the an i64 [-9223372036854775808, 9223372036854775807] into the u64 domain [0, 18446744073709551615]. So for example 0 in i64 is 9223372036854775808 in u64.

Here is what I have done.

    let x: i64 = -10;
    let x_transform = ((x as u64) ^ (1 << 63)) & (1 << 63) | (x as u64 & (u64::MAX >> 1));
    let x_original = ((x_transform as i64) ^ (1 << 63)) & (1 << 63) | (x_transform & (u64::MAX >> 1)) as i64;
    
    println!("x_transform {}", x_transform);
    println!("x_original {} {}", x_original, x_original == x);

yielding

x_transform 9223372036854775798

x_original -10 true

Is there a built in way to do this, because it seems too verbose, and error prone?


Solution

  • From a performance view it doesn't really matter how you write it, a quick check on godbot shows both the wrapping and the bit shifty versions compile to the same machine code. But I'd argue the variants with wrapping are way more readable and convey the intent better.

    pub fn wrap_to_u64(x: i64) -> u64 {
        (x as u64).wrapping_add(u64::MAX/2 + 1)
    }
    pub fn wrap_to_i64(x: u64) -> i64 {
        x.wrapping_sub(u64::MAX/2 + 1) as i64
    }
    pub fn to_u64(x: i64) -> u64 {
        ((x as u64) ^ (1 << 63)) & (1 << 63) | (x as u64 & (u64::MAX >> 1))
    }
    pub fn to_i64(x: u64) -> i64 {
        ((x as i64) ^ (1 << 63)) & (1 << 63) | (x & (u64::MAX >> 1)) as i64
    }
    
    example::wrap_to_u64:
            movabs  rax, -9223372036854775808
            xor     rax, rdi
            ret
    
    example::wrap_to_i64:
            movabs  rax, -9223372036854775808
            xor     rax, rdi
            ret
    
    example::to_u64:
            movabs  rax, -9223372036854775808
            xor     rax, rdi
            ret
    
    example::to_i64:
            movabs  rax, -9223372036854775808
            xor     rax, rdi
            ret
    

    The lesson to learn is that unless you have a very specific optimization probably the compiler will outperform you.