Number Conversions
Number Conversions
When working with numeric types in Rust, you'll often need to convert between different integer sizes (like i32 to i64) or perform arithmetic that might overflow. While Rust's as keyword provides basic casts, it can silently truncate or wrap values, leading to subtle bugs. The standard library provides safer alternatives.
Safe Type Conversions
Rust's TryFrom and TryInto traits allow fallible conversions that return Result instead of silently changing values:
use std::convert::TryFrom;
let big: i64 = 1000;
let small: Result<i16, _> = i16::try_from(big); // Ok(1000)
let too_big: i64 = 100_000;
// Err(...)
let overflow: Result<i16, _> = i16::try_from(too_big);Safe Arithmetic Operations
Rust integers provide methods for safe arithmetic that handle overflow explicitly:
-
Checked operations return
Option<T>, givingNoneon overflow:rust let x: u8 = 250; assert_eq!(x.checked_add(10), None); // Would overflow assert_eq!(x.checked_add(5), Some(255)); -
Saturating operations clamp at the type's bounds:
rust let x: u8 = 250; assert_eq!(x.saturating_add(10), 255); // Clamped to max assert_eq!(x.saturating_sub(255), 0); // Clamped to min -
Wrapping operations wrap around on overflow (like C behavior):
rust let x: u8 = 250; assert_eq!(x.wrapping_add(10), 4); // 260 wraps to 4
Your Task
Implement the following functions to demonstrate safe numeric conversions and arithmetic:
-
safe_i32_to_i16(value: i32) -> Option<i16>- Convert an
i32toi16, returningNoneif the value doesn't fit.
- Convert an
-
safe_u64_to_u32(value: u64) -> Option<u32>- Convert a
u64tou32, returningNoneif the value doesn't fit.
- Convert a
-
safe_i64_to_usize(value: i64) -> Option<usize>- Convert an
i64tousize, returningNoneif the value is negative or too large.
- Convert an
-
checked_multiply(a: i32, b: i32) -> Option<i32>- Multiply two
i32values, returningNoneon overflow.
- Multiply two
-
checked_power(base: u32, exp: u32) -> Option<u32>- Calculate
base^exp, returningNoneon overflow.
- Calculate
-
saturating_sum(numbers: &[i32]) -> i32- Sum all numbers using saturating arithmetic
(clamp at
i32::MINori32::MAX).
- Sum all numbers using saturating arithmetic
(clamp at
-
wrapping_factorial(n: u32) -> u32- Calculate
n!using wrapping arithmetic (allows overflow to wrap around).
- Calculate
-
safe_average(numbers: &[i64]) -> Option<i64>- Calculate the average of numbers, returning
Noneif the sum would overflow or the slice is empty.
- Calculate the average of numbers, returning
Examples
// Safe conversions
assert_eq!(safe_i32_to_i16(1000), Some(1000));
assert_eq!(safe_i32_to_i16(100_000), None);
// Checked arithmetic
assert_eq!(checked_multiply(1000, 1000), Some(1_000_000));
// Overflow
assert_eq!(checked_multiply(100_000, 100_000), None);
// Saturating arithmetic
assert_eq!(saturating_sum(&[i32::MAX, 1]), i32::MAX);
assert_eq!(saturating_sum(&[i32::MIN, -1]), i32::MIN);
// Wrapping arithmetic
assert_eq!(wrapping_factorial(5), 120);
// Wrapped value
assert_eq!(wrapping_factorial(20), 2_192_834_560);Hints
Click here to reveal hints
- Use
i16::try_from(value).ok()to convertTryFromresults toOption. - For
safe_i64_to_usize, remember that negative values and values larger thanusize::MAXshould both returnNone. - The
checked_powmethod works likechecked_mulbut for exponentiation. - For
saturating_sum, useIterator::foldwithsaturating_add. - For
safe_average, first check if the slice is empty, then use checked arithmetic to compute the sum before dividing. - Remember that
wrapping_mulcontinues even when overflow occurs.
Run to execute your code and see test results here.