rust 如何在u64域中表示i64?

y53ybaqx  于 2022-11-24  发布在  其他
关注(0)|答案(2)|浏览(235)

如何将一个i64 [-9223372036854775808,9223372036854775807]表示到u64域[0,18446744073709551615]中?例如,i64中的0在u64中是9223372036854775808。
这就是我所做的。

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

屈服的
x转换9223372036854775798
x_原始-10真
是否有一种内置的方法来实现这一点,因为它似乎太冗长,容易出错?

ibrsph3r

ibrsph3r1#

从性能的Angular 看,你怎么写并不重要,快速检查一下godbot就可以发现, Package 和移位版本都编译成了相同的机器码。但我认为,带有 Package 的变体可读性更强,更好地传达了意图。
第一个
要吸取的教训是,除非你有一个非常具体的优化,否则编译器可能会比你更好。

pxy2qtax

pxy2qtax2#

最简单的解决方案是只转换2的补码表示,而不是使用偏移二进制:

let x_transform = u64::from_ne_bytes(x.to_ne_bytes());
let x_original = i64::from_ne_bytes(x_transform.to_ne_bytes());

然而据维基所言:
偏移二进制可通过反转最高有效位而转换成二进制补码。
因此,您可以这样做,并在实际翻译中使用不易出错的2的补码:

pub fn convert1(x: i64) -> u64 {
        ((x as u64) ^ (1 << 63)) & (1 << 63) | (x as u64 & (u64::MAX >> 1))
}

pub fn convert3(x: i64) -> u64 {
    // manipulating the bytes in transit requires
    // knowing the MSB, use LE as that's the most
    // commmon by far
    let mut bytes = x.to_le_bytes();
    bytes[7] ^= 0x80;
    u64::from_le_bytes(bytes)
}

pub fn convert4(x: i64) -> u64 {
    u64::from_ne_bytes((x ^ i64::MIN).to_ne_bytes())
}

all produce the exact same x86_64 code

movabs  rax, -9223372036854775808
        xor     rax, rdi
        ret

相关问题