Можно ли усечь BigInteger до i32 в Rust? - PullRequest
0 голосов
/ 23 мая 2018

В Java intValue() возвращает усеченную часть экземпляра BigInteger.Я написал аналогичную программу на Rust, но она не усекается:

extern crate num;

use num::bigint::{BigInt, RandBigInt};
use num::ToPrimitive;

fn main() {
    println!("Hello, world!");
    truncate_num(
        BigInt::parse_bytes(b"423445324324324324234324", 10).unwrap(),
        BigInt::parse_bytes(b"22447", 10).unwrap(),
    );
}

fn truncate_num(num1: BigInt, num2: BigInt) -> i32 {
    println!("Truncation of {} is {:?}.", num1, num1.to_i32());
    println!("Truncation of {} is {:?}.", num2, num2.to_i32());
    return 0;
}

Вывод, который я получаю из этого

Hello, world!
Truncation of 423445324324324324234324 is None.
Truncation of 22447 is Some(22447).

Как мне добиться этого в Rust?Должен ли я попробовать преобразование в String и затем обрезать вручную?Это будет моим последним средством.

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Java intValue() возвращает младшие 32 бита целого числа.Это можно сделать с помощью побитовой операции И x & 0xffffffff.A BigInt в Rust не поддерживает побитовое манипулирование, но вы можете сначала преобразовать его в BigUint, который поддерживает таких операций.

fn truncate_biguint_to_u32(a: &BigUint) -> u32 {
    use std::u32;
    let mask = BigUint::from(u32::MAX);
    (a & mask).to_u32().unwrap()
}

Преобразование BigInt в BigUint будет успешным, только если оно не отрицательное.Если BigInt является отрицательным (-x), мы могли бы найти младшие 32 бита его абсолютного значения (x), а затем аннулировать результат.

fn truncate_bigint_to_u32(a: &BigInt) -> u32 {
    use num_traits::Signed;

    let was_negative = a.is_negative();
    let abs = a.abs().to_biguint().unwrap();
    let mut truncated = truncate_biguint_to_u32(&abs);
    if was_negative {
        truncated.wrapping_neg()
    } else {
        truncated
    }
}

Демо

Вы можете использовать truncate_bigint_to_u32(a) as i32, если вам нужен номер со знаком.


Существует также метод to_signed_bytes_le(), с помощью которого вы можете извлекать байты и декодировать их.непосредственно в примитивное целое число:

fn truncate_bigint_to_u32_slow(a: &BigInt) -> u32 {
    let mut bytes = a.to_signed_bytes_le();
    bytes.resize(4, 0);
    bytes[0] as u32 | (bytes[1] as u32) << 8 | (bytes[2] as u32) << 16 | (bytes[3] as u32) << 24
}

Этот метод чрезвычайно медленный по сравнению с описанными выше методами, и я не рекомендую его использовать.

0 голосов
/ 23 мая 2018

Нет естественного усечения большого целого в меньшее.Либо он подходит, либо вам нужно решить, какое значение вы хотите.

Вы можете сделать это:

println!("Truncation of {} is {:?}.", num1, num1.to_i32().unwrap_or(-1));

или

println!("Truncation of {} is {:?}.", num1, num1.to_i32().unwrap_or(std::i32::MAX));

, но логика вашего приложения, вероятно, должна диктоватькаково желаемое поведение, когда возвращаемая опция не содержит значения.

...