num-bigint is a foundational Rust crate that provides arbitrary-precision integer types. In Rust, built-in integer types like `i32`, `u64`, `isize` have fixed sizes, meaning they can only represent numbers up to a certain maximum value. When computations involve numbers that exceed these limits, standard types would either overflow (leading to incorrect results) or panic in debug mode.
`num-bigint` solves this problem by offering `BigInt` for signed arbitrary-precision integers and `BigUint` for unsigned arbitrary-precision integers. These types can represent numbers of virtually any magnitude, limited only by available memory. This is crucial for applications requiring high-precision arithmetic, such as cryptography, scientific simulations, financial calculations, or working with extremely large combinatorial numbers.
Key features include:
* Arbitrary Precision: Numbers can grow as large as needed, limited only by available memory.
* Comprehensive Arithmetic Operations: Supports standard operations like addition, subtraction, multiplication, division, modulo, exponentiation, bitwise operations, etc., mimicking standard integer behavior.
* Conversions: Easy conversion to and from built-in integer types, strings, and byte arrays.
* Comparisons: Standard comparison operators (`==`, `!=`, `<`, `>`, `<=`, `>=`) are supported.
* Trait-based Design: Integrates well with Rust's numeric ecosystem through traits from the `num-traits` crate, providing common numeric functionality.
To use `num-bigint`, you add it as a dependency in your `Cargo.toml` file.
Example Code
```rust
// First, add the following to your Cargo.toml:
// [dependencies]
// num-bigint = "0.4"
// num-traits = "0.2" # Often used alongside for traits like `Zero`, `One`, `FromPrimitive`
use num_bigint::{BigInt, BigUint, Sign};
use num_traits::{Zero, One, FromPrimitive}; // For convenient constants and conversions
use std::str::FromStr; // For parsing from string
fn main() {
println!("--- num-bigint Example ---");
// 1. Creating BigInt and BigUint instances
// From string representation
let big_int_pos = BigInt::from_str("123456789012345678901234567890").unwrap();
let big_int_neg = BigInt::parse_bytes(b"-987654321098765432109876543210", 10).unwrap();
let big_uint = BigUint::from_str("112233445566778899001122334455").unwrap();
println!("BigInt (positive): {}", big_int_pos);
println!("BigInt (negative): {}", big_int_neg);
println!("BigUint: {}", big_uint);
// From smaller built-in types
let small_int = BigInt::from(100i64);
let small_uint_max = BigUint::from_u128(u128::MAX).unwrap(); // Or from_u64, etc.
println!("BigInt from i64: {}", small_int);
println!("BigUint from u128::MAX: {}", small_uint_max);
// 2. Arithmetic Operations
let sum_big_int = &big_int_pos + &big_int_neg;
println!("\nSum (big_int_pos + big_int_neg): {}", sum_big_int);
let product_big_uint = &big_uint * BigUint::from(2u8);
println!("Product (big_uint * 2): {}", product_big_uint);
let difference = &big_int_pos - BigInt::from_u64(1).unwrap();
println!("Difference (big_int_pos - 1): {}", difference);
let division = &big_int_pos / BigInt::from(100);
println!("Division (big_int_pos / 100): {}", division);
let modulus = &big_int_pos % BigInt::from(100);
println!("Modulus (big_int_pos % 100): {}", modulus);
// 3. Comparisons
println!("\nIs big_int_pos > big_int_neg? {}", big_int_pos > big_int_neg);
println!("Is big_int_pos == BigInt::from(0)? {}", big_int_pos == BigInt::zero());
println!("Is big_uint == BigUint::one()? {}", big_uint == BigUint::one());
// 4. Getting sign and converting back (if possible)
println!("\nSign of big_int_pos: {:?}", big_int_pos.sign());
println!("Sign of sum_big_int: {:?}", sum_big_int.sign());
// Try to convert sum_big_int back to i64 (will fail if too large or negative)
match sum_big_int.to_i64() {
Some(val) => println!("sum_big_int fits in i64: {}", val),
None => println!("sum_big_int is too large or too small for i64."),
}
// Example of a truly massive number that would never fit in standard types
// Calculate 2^200
let base = BigUint::from(2u8);
let exponent = 200u32;
let power_of_two = base.pow(exponent);
println!("\n2^{}: {}", exponent, power_of_two);
println!("Number of digits in 2^{}: {}", exponent, power_of_two.to_string().len());
// Another example: factorial of a large number
let mut factorial_num = BigUint::from(100u32);
let mut result = BigUint::one();
for i in 1..=factorial_num.to_u32().unwrap() {
result *= BigUint::from(i);
}
println!("\n{}!: {}", factorial_num, result);
println!("Number of digits in {}!: {}", factorial_num, result.to_string().len());
}
```








num-bigint