可以将 BigInteger 截断为 Rust 中的 i32 吗?
Can a BigInteger be truncated to an i32 in Rust?
在 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
然后手动截断吗?这是我最后的选择。
没有自然地将一个大整数截断为一个较小的整数。要么它适合,要么你必须决定你想要什么价值。
你可以这样做:
println!("Truncation of {} is {:?}.", num1, num1.to_i32().unwrap_or(-1));
或
println!("Truncation of {} is {:?}.", num1, num1.to_i32().unwrap_or(std::i32::MAX));
但是当返回的选项不包含任何值时,您的应用程序逻辑可能应该规定所需的行为。
Java的intValue()
returns the lowest 32 bits of the integer. This could be done by a bitwise-AND operation x & 0xffffffff
. A BigInt
in Rust doesn't support bitwise manipulation, but you could first convert it to a BigUint
which supports这样的操作。
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),我们可以找到它的绝对值(x)的最低32位,然后取反。
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
}
与上述方法相比,此方法非常慢,我不建议使用它。
在 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
然后手动截断吗?这是我最后的选择。
没有自然地将一个大整数截断为一个较小的整数。要么它适合,要么你必须决定你想要什么价值。
你可以这样做:
println!("Truncation of {} is {:?}.", num1, num1.to_i32().unwrap_or(-1));
或
println!("Truncation of {} is {:?}.", num1, num1.to_i32().unwrap_or(std::i32::MAX));
但是当返回的选项不包含任何值时,您的应用程序逻辑可能应该规定所需的行为。
Java的intValue()
returns the lowest 32 bits of the integer. This could be done by a bitwise-AND operation x & 0xffffffff
. A BigInt
in Rust doesn't support bitwise manipulation, but you could first convert it to a BigUint
which supports这样的操作。
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),我们可以找到它的绝对值(x)的最低32位,然后取反。
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
}
与上述方法相比,此方法非常慢,我不建议使用它。