Может ли BigInteger быть усечен до i32 в ржавчине?
В 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 ответа:
Java
intValue()
возвращает наименьшие 32 бита целого числа. Это может быть сделано с помощью побитовой операции-иx & 0xffffffff
. А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 }
Нет никакого естественного усечения большого целого числа в меньшее. Либо он подходит, либо вы должны решить, какую ценность вы хотите.
Можно сделать так:
println!("Truncation of {} is {:?}.", num1, num1.to_i32().unwrap_or(-1));
Или
println!("Truncation of {} is {:?}.", num1, num1.to_i32().unwrap_or(std::i32::MAX));
Но логика вашего приложения, вероятно, должна диктовать, каково желаемое поведение, когда возвращаемый параметр не содержит значения.