use crate::fixed_point::domains::symbolic::rational::rational_number::OverflowDetected;
use crate::fixed_point::i256::I256;
pub fn gcd_unsigned(mut a: u128, mut b: u128) -> u128 {
while b != 0 {
let temp = b;
b = a % b;
a = temp;
}
if a == 0 { 1 } else { a }
}
fn gcd_i256(mut a: I256, mut b: I256) -> I256 {
if a.is_negative() { a = -a; }
if b.is_negative() { b = -b; }
while !b.is_zero() {
let temp = b;
b = a % b;
a = temp;
}
if a.is_zero() { I256::from_i128(1) } else { a }
}
fn i256_reduce_to_i128(num: I256, den: I256) -> Result<(i128, u128), OverflowDetected> {
if num.is_zero() { return Ok((0, 1)); }
let gcd = gcd_i256(num, den);
let reduced_num = num / gcd;
let reduced_den = den / gcd;
let (final_num, final_den) = if reduced_den.is_negative() {
(-reduced_num, -reduced_den)
} else {
(reduced_num, reduced_den)
};
if final_num.fits_in_i128() && final_den.fits_in_i128() {
Ok((final_num.as_i128(), final_den.as_i128() as u128))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn add_i8_rational(a_num: i8, a_den: u8, b_num: i8, b_den: u8) -> Result<(i8, u8), OverflowDetected> {
if a_num == 0 { return Ok((b_num, b_den)); }
if b_num == 0 { return Ok((a_num, a_den)); }
let a_expanded = (a_num as i16).checked_mul(b_den as i16)
.ok_or(OverflowDetected::TierOverflow)?;
let b_expanded = (b_num as i16).checked_mul(a_den as i16)
.ok_or(OverflowDetected::TierOverflow)?;
let common_denominator = (a_den as u16).checked_mul(b_den as u16)
.ok_or(OverflowDetected::TierOverflow)?;
let result_numerator = a_expanded.checked_add(b_expanded)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs() as u128, common_denominator as u128);
let reduced_num = (result_numerator as i128) / (g as i128);
let reduced_den = (common_denominator as u128) / g;
if reduced_num >= i8::MIN as i128 && reduced_num <= i8::MAX as i128 &&
reduced_den <= u8::MAX as u128 {
Ok((reduced_num as i8, reduced_den as u8))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn sub_i8_rational(a_num: i8, a_den: u8, b_num: i8, b_den: u8) -> Result<(i8, u8), OverflowDetected> {
if b_num == 0 { return Ok((a_num, a_den)); }
let a_expanded = (a_num as i16).checked_mul(b_den as i16)
.ok_or(OverflowDetected::TierOverflow)?;
let b_expanded = (b_num as i16).checked_mul(a_den as i16)
.ok_or(OverflowDetected::TierOverflow)?;
let common_denominator = (a_den as u16).checked_mul(b_den as u16)
.ok_or(OverflowDetected::TierOverflow)?;
let result_numerator = a_expanded.checked_sub(b_expanded)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs() as u128, common_denominator as u128);
let reduced_num = (result_numerator as i128) / (g as i128);
let reduced_den = (common_denominator as u128) / g;
if reduced_num >= i8::MIN as i128 && reduced_num <= i8::MAX as i128 &&
reduced_den <= u8::MAX as u128 {
Ok((reduced_num as i8, reduced_den as u8))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn mul_i8_rational(a_num: i8, a_den: u8, b_num: i8, b_den: u8) -> Result<(i8, u8), OverflowDetected> {
if a_num == 0 || b_num == 0 { return Ok((0, 1)); }
if a_num == 1 && a_den == 1 { return Ok((b_num, b_den)); }
if b_num == 1 && b_den == 1 { return Ok((a_num, a_den)); }
let result_numerator = (a_num as i16).checked_mul(b_num as i16)
.ok_or(OverflowDetected::TierOverflow)?;
let result_denominator = (a_den as u16).checked_mul(b_den as u16)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs() as u128, result_denominator as u128);
let reduced_num = (result_numerator as i128) / (g as i128);
let reduced_den = (result_denominator as u128) / g;
if reduced_num >= i8::MIN as i128 && reduced_num <= i8::MAX as i128 &&
reduced_den <= u8::MAX as u128 {
Ok((reduced_num as i8, reduced_den as u8))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn div_i8_rational(a_num: i8, a_den: u8, b_num: i8, b_den: u8) -> Result<(i8, u8), OverflowDetected> {
if b_num == 0 { return Err(OverflowDetected::PrecisionLoss); }
if a_num == 0 { return Ok((0, 1)); }
if b_num == 1 && b_den == 1 { return Ok((a_num, a_den)); }
let result_numerator = (a_num as i16).checked_mul(b_den as i16)
.ok_or(OverflowDetected::TierOverflow)?;
let result_denominator = (a_den as u16).checked_mul(b_num.abs() as u16)
.ok_or(OverflowDetected::TierOverflow)?;
let final_numerator = if b_num < 0 { -result_numerator } else { result_numerator };
let g = gcd_unsigned(final_numerator.unsigned_abs() as u128, result_denominator as u128);
let reduced_num = (final_numerator as i128) / (g as i128);
let reduced_den = (result_denominator as u128) / g;
if reduced_num >= i8::MIN as i128 && reduced_num <= i8::MAX as i128 &&
reduced_den <= u8::MAX as u128 {
Ok((reduced_num as i8, reduced_den as u8))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn add_i16_rational(a_num: i16, a_den: u16, b_num: i16, b_den: u16) -> Result<(i16, u16), OverflowDetected> {
if a_num == 0 { return Ok((b_num, b_den)); }
if b_num == 0 { return Ok((a_num, a_den)); }
let a_expanded = (a_num as i32).checked_mul(b_den as i32)
.ok_or(OverflowDetected::TierOverflow)?;
let b_expanded = (b_num as i32).checked_mul(a_den as i32)
.ok_or(OverflowDetected::TierOverflow)?;
let common_denominator = (a_den as u32).checked_mul(b_den as u32)
.ok_or(OverflowDetected::TierOverflow)?;
let result_numerator = a_expanded.checked_add(b_expanded)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs() as u128, common_denominator as u128);
let reduced_num = (result_numerator as i128) / (g as i128);
let reduced_den = (common_denominator as u128) / g;
if reduced_num >= i16::MIN as i128 && reduced_num <= i16::MAX as i128 &&
reduced_den <= u16::MAX as u128 {
Ok((reduced_num as i16, reduced_den as u16))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn sub_i16_rational(a_num: i16, a_den: u16, b_num: i16, b_den: u16) -> Result<(i16, u16), OverflowDetected> {
if b_num == 0 { return Ok((a_num, a_den)); }
let a_expanded = (a_num as i32).checked_mul(b_den as i32)
.ok_or(OverflowDetected::TierOverflow)?;
let b_expanded = (b_num as i32).checked_mul(a_den as i32)
.ok_or(OverflowDetected::TierOverflow)?;
let common_denominator = (a_den as u32).checked_mul(b_den as u32)
.ok_or(OverflowDetected::TierOverflow)?;
let result_numerator = a_expanded.checked_sub(b_expanded)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs() as u128, common_denominator as u128);
let reduced_num = (result_numerator as i128) / (g as i128);
let reduced_den = (common_denominator as u128) / g;
if reduced_num >= i16::MIN as i128 && reduced_num <= i16::MAX as i128 &&
reduced_den <= u16::MAX as u128 {
Ok((reduced_num as i16, reduced_den as u16))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn mul_i16_rational(a_num: i16, a_den: u16, b_num: i16, b_den: u16) -> Result<(i16, u16), OverflowDetected> {
if a_num == 0 || b_num == 0 { return Ok((0, 1)); }
if a_num == 1 && a_den == 1 { return Ok((b_num, b_den)); }
if b_num == 1 && b_den == 1 { return Ok((a_num, a_den)); }
let result_numerator = (a_num as i32).checked_mul(b_num as i32)
.ok_or(OverflowDetected::TierOverflow)?;
let result_denominator = (a_den as u32).checked_mul(b_den as u32)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs() as u128, result_denominator as u128);
let reduced_num = (result_numerator as i128) / (g as i128);
let reduced_den = (result_denominator as u128) / g;
if reduced_num >= i16::MIN as i128 && reduced_num <= i16::MAX as i128 &&
reduced_den <= u16::MAX as u128 {
Ok((reduced_num as i16, reduced_den as u16))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn div_i16_rational(a_num: i16, a_den: u16, b_num: i16, b_den: u16) -> Result<(i16, u16), OverflowDetected> {
if b_num == 0 { return Err(OverflowDetected::PrecisionLoss); }
if a_num == 0 { return Ok((0, 1)); }
if b_num == 1 && b_den == 1 { return Ok((a_num, a_den)); }
let result_numerator = (a_num as i32).checked_mul(b_den as i32)
.ok_or(OverflowDetected::TierOverflow)?;
let result_denominator = (a_den as u32).checked_mul(b_num.abs() as u32)
.ok_or(OverflowDetected::TierOverflow)?;
let final_numerator = if b_num < 0 { -result_numerator } else { result_numerator };
let g = gcd_unsigned(final_numerator.unsigned_abs() as u128, result_denominator as u128);
let reduced_num = (final_numerator as i128) / (g as i128);
let reduced_den = (result_denominator as u128) / g;
if reduced_num >= i16::MIN as i128 && reduced_num <= i16::MAX as i128 &&
reduced_den <= u16::MAX as u128 {
Ok((reduced_num as i16, reduced_den as u16))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn add_i32_rational(a_num: i32, a_den: u32, b_num: i32, b_den: u32) -> Result<(i32, u32), OverflowDetected> {
if a_num == 0 { return Ok((b_num, b_den)); }
if b_num == 0 { return Ok((a_num, a_den)); }
let a_expanded = (a_num as i64).checked_mul(b_den as i64)
.ok_or(OverflowDetected::TierOverflow)?;
let b_expanded = (b_num as i64).checked_mul(a_den as i64)
.ok_or(OverflowDetected::TierOverflow)?;
let common_denominator = (a_den as u64).checked_mul(b_den as u64)
.ok_or(OverflowDetected::TierOverflow)?;
let result_numerator = a_expanded.checked_add(b_expanded)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs() as u128, common_denominator as u128);
let reduced_num = (result_numerator as i128) / (g as i128);
let reduced_den = (common_denominator as u128) / g;
if reduced_num >= i32::MIN as i128 && reduced_num <= i32::MAX as i128 &&
reduced_den <= u32::MAX as u128 {
Ok((reduced_num as i32, reduced_den as u32))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn sub_i32_rational(a_num: i32, a_den: u32, b_num: i32, b_den: u32) -> Result<(i32, u32), OverflowDetected> {
if b_num == 0 { return Ok((a_num, a_den)); }
let a_expanded = (a_num as i64).checked_mul(b_den as i64)
.ok_or(OverflowDetected::TierOverflow)?;
let b_expanded = (b_num as i64).checked_mul(a_den as i64)
.ok_or(OverflowDetected::TierOverflow)?;
let common_denominator = (a_den as u64).checked_mul(b_den as u64)
.ok_or(OverflowDetected::TierOverflow)?;
let result_numerator = a_expanded.checked_sub(b_expanded)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs() as u128, common_denominator as u128);
let reduced_num = (result_numerator as i128) / (g as i128);
let reduced_den = (common_denominator as u128) / g;
if reduced_num >= i32::MIN as i128 && reduced_num <= i32::MAX as i128 &&
reduced_den <= u32::MAX as u128 {
Ok((reduced_num as i32, reduced_den as u32))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn mul_i32_rational(a_num: i32, a_den: u32, b_num: i32, b_den: u32) -> Result<(i32, u32), OverflowDetected> {
if a_num == 0 || b_num == 0 { return Ok((0, 1)); }
if a_num == 1 && a_den == 1 { return Ok((b_num, b_den)); }
if b_num == 1 && b_den == 1 { return Ok((a_num, a_den)); }
let result_numerator = (a_num as i64).checked_mul(b_num as i64)
.ok_or(OverflowDetected::TierOverflow)?;
let result_denominator = (a_den as u64).checked_mul(b_den as u64)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs() as u128, result_denominator as u128);
let reduced_num = (result_numerator as i128) / (g as i128);
let reduced_den = (result_denominator as u128) / g;
if reduced_num >= i32::MIN as i128 && reduced_num <= i32::MAX as i128 &&
reduced_den <= u32::MAX as u128 {
Ok((reduced_num as i32, reduced_den as u32))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn div_i32_rational(a_num: i32, a_den: u32, b_num: i32, b_den: u32) -> Result<(i32, u32), OverflowDetected> {
if b_num == 0 { return Err(OverflowDetected::PrecisionLoss); }
if a_num == 0 { return Ok((0, 1)); }
if b_num == 1 && b_den == 1 { return Ok((a_num, a_den)); }
let result_numerator = (a_num as i64).checked_mul(b_den as i64)
.ok_or(OverflowDetected::TierOverflow)?;
let result_denominator = (a_den as u64).checked_mul(b_num.abs() as u64)
.ok_or(OverflowDetected::TierOverflow)?;
let final_numerator = if b_num < 0 { -result_numerator } else { result_numerator };
let g = gcd_unsigned(final_numerator.unsigned_abs() as u128, result_denominator as u128);
let reduced_num = (final_numerator as i128) / (g as i128);
let reduced_den = (result_denominator as u128) / g;
if reduced_num >= i32::MIN as i128 && reduced_num <= i32::MAX as i128 &&
reduced_den <= u32::MAX as u128 {
Ok((reduced_num as i32, reduced_den as u32))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn add_i64_rational(a_num: i64, a_den: u64, b_num: i64, b_den: u64) -> Result<(i64, u64), OverflowDetected> {
if a_num == 0 { return Ok((b_num, b_den)); }
if b_num == 0 { return Ok((a_num, a_den)); }
let a_expanded = (a_num as i128).checked_mul(b_den as i128)
.ok_or(OverflowDetected::TierOverflow)?;
let b_expanded = (b_num as i128).checked_mul(a_den as i128)
.ok_or(OverflowDetected::TierOverflow)?;
let common_denominator = (a_den as u128).checked_mul(b_den as u128)
.ok_or(OverflowDetected::TierOverflow)?;
let result_numerator = a_expanded.checked_add(b_expanded)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs(), common_denominator);
let reduced_num = result_numerator / (g as i128);
let reduced_den = common_denominator / g;
if reduced_num >= i64::MIN as i128 && reduced_num <= i64::MAX as i128 &&
reduced_den <= u64::MAX as u128 {
Ok((reduced_num as i64, reduced_den as u64))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn sub_i64_rational(a_num: i64, a_den: u64, b_num: i64, b_den: u64) -> Result<(i64, u64), OverflowDetected> {
if b_num == 0 { return Ok((a_num, a_den)); }
let a_expanded = (a_num as i128).checked_mul(b_den as i128)
.ok_or(OverflowDetected::TierOverflow)?;
let b_expanded = (b_num as i128).checked_mul(a_den as i128)
.ok_or(OverflowDetected::TierOverflow)?;
let common_denominator = (a_den as u128).checked_mul(b_den as u128)
.ok_or(OverflowDetected::TierOverflow)?;
let result_numerator = a_expanded.checked_sub(b_expanded)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs(), common_denominator);
let reduced_num = result_numerator / (g as i128);
let reduced_den = common_denominator / g;
if reduced_num >= i64::MIN as i128 && reduced_num <= i64::MAX as i128 &&
reduced_den <= u64::MAX as u128 {
Ok((reduced_num as i64, reduced_den as u64))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn mul_i64_rational(a_num: i64, a_den: u64, b_num: i64, b_den: u64) -> Result<(i64, u64), OverflowDetected> {
if a_num == 0 || b_num == 0 { return Ok((0, 1)); }
if a_num == 1 && a_den == 1 { return Ok((b_num, b_den)); }
if b_num == 1 && b_den == 1 { return Ok((a_num, a_den)); }
let result_numerator = (a_num as i128).checked_mul(b_num as i128)
.ok_or(OverflowDetected::TierOverflow)?;
let result_denominator = (a_den as u128).checked_mul(b_den as u128)
.ok_or(OverflowDetected::TierOverflow)?;
let g = gcd_unsigned(result_numerator.unsigned_abs(), result_denominator);
let reduced_num = result_numerator / (g as i128);
let reduced_den = result_denominator / g;
if reduced_num >= i64::MIN as i128 && reduced_num <= i64::MAX as i128 &&
reduced_den <= u64::MAX as u128 {
Ok((reduced_num as i64, reduced_den as u64))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn div_i64_rational(a_num: i64, a_den: u64, b_num: i64, b_den: u64) -> Result<(i64, u64), OverflowDetected> {
if b_num == 0 { return Err(OverflowDetected::PrecisionLoss); }
if a_num == 0 { return Ok((0, 1)); }
if b_num == 1 && b_den == 1 { return Ok((a_num, a_den)); }
let result_numerator = (a_num as i128).checked_mul(b_den as i128)
.ok_or(OverflowDetected::TierOverflow)?;
let result_denominator = (a_den as u128).checked_mul(b_num.abs() as u128)
.ok_or(OverflowDetected::TierOverflow)?;
let final_numerator = if b_num < 0 { -result_numerator } else { result_numerator };
let g = gcd_unsigned(final_numerator.unsigned_abs(), result_denominator);
let reduced_num = final_numerator / (g as i128);
let reduced_den = result_denominator / g;
if reduced_num >= i64::MIN as i128 && reduced_num <= i64::MAX as i128 &&
reduced_den <= u64::MAX as u128 {
Ok((reduced_num as i64, reduced_den as u64))
} else {
Err(OverflowDetected::TierOverflow)
}
}
pub fn add_i128_rational(a_num: i128, a_den: u128, b_num: i128, b_den: u128) -> Result<(i128, u128), OverflowDetected> {
if a_num == 0 { return Ok((b_num, b_den)); }
if b_num == 0 { return Ok((a_num, a_den)); }
let a = I256::from_i128(a_num);
let b = I256::from_i128(b_num);
let ad = I256::from_u128(a_den);
let bd = I256::from_u128(b_den);
let result_num = a * bd + b * ad;
let result_den = ad * bd;
i256_reduce_to_i128(result_num, result_den)
}
pub fn sub_i128_rational(a_num: i128, a_den: u128, b_num: i128, b_den: u128) -> Result<(i128, u128), OverflowDetected> {
if b_num == 0 { return Ok((a_num, a_den)); }
let a = I256::from_i128(a_num);
let b = I256::from_i128(b_num);
let ad = I256::from_u128(a_den);
let bd = I256::from_u128(b_den);
let result_num = a * bd - b * ad;
let result_den = ad * bd;
i256_reduce_to_i128(result_num, result_den)
}
pub fn mul_i128_rational(a_num: i128, a_den: u128, b_num: i128, b_den: u128) -> Result<(i128, u128), OverflowDetected> {
if a_num == 0 || b_num == 0 { return Ok((0, 1)); }
if a_num == 1 && a_den == 1 { return Ok((b_num, b_den)); }
if b_num == 1 && b_den == 1 { return Ok((a_num, a_den)); }
let a = I256::from_i128(a_num);
let b = I256::from_i128(b_num);
let ad = I256::from_u128(a_den);
let bd = I256::from_u128(b_den);
let result_num = a * b;
let result_den = ad * bd;
i256_reduce_to_i128(result_num, result_den)
}
pub fn div_i128_rational(a_num: i128, a_den: u128, b_num: i128, b_den: u128) -> Result<(i128, u128), OverflowDetected> {
if b_num == 0 { return Err(OverflowDetected::PrecisionLoss); }
if a_num == 0 { return Ok((0, 1)); }
if b_num == 1 && b_den == 1 { return Ok((a_num, a_den)); }
let a = I256::from_i128(a_num);
let bd = I256::from_u128(b_den);
let ad = I256::from_u128(a_den);
let b_abs = I256::from_u128(b_num.unsigned_abs());
let result_num = a * bd;
let result_den = ad * b_abs;
let final_num = if b_num < 0 { -result_num } else { result_num };
i256_reduce_to_i128(final_num, result_den)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_i8_rational_addition() {
let result = add_i8_rational(1, 3, 1, 6).unwrap();
assert_eq!(result, (1, 2));
let overflow = add_i8_rational(127, 1, 1, 1);
assert!(overflow.is_err());
}
#[test]
fn test_i8_rational_multiplication() {
let result = mul_i8_rational(1, 2, 2, 3).unwrap();
assert_eq!(result, (1, 3));
let zero_result = mul_i8_rational(0, 1, 5, 7).unwrap();
assert_eq!(zero_result, (0, 1));
}
#[test]
fn test_i8_rational_division() {
let result = div_i8_rational(1, 2, 1, 4).unwrap();
assert_eq!(result, (2, 1));
let div_zero = div_i8_rational(1, 2, 0, 1);
assert!(div_zero.is_err());
}
#[test]
fn test_mathematical_identities() {
let result = add_i8_rational(3, 4, 0, 1).unwrap();
assert_eq!(result, (3, 4));
let result = mul_i8_rational(3, 4, 1, 1).unwrap();
assert_eq!(result, (3, 4));
let result = mul_i8_rational(3, 4, 0, 1).unwrap();
assert_eq!(result, (0, 1));
}
#[test]
fn test_cross_tier_consistency_addition() {
let i8_result = add_i8_rational(1, 3, 1, 6).unwrap();
let i16_result = add_i16_rational(1, 3, 1, 6).unwrap();
let i32_result = add_i32_rational(1, 3, 1, 6).unwrap();
let i64_result = add_i64_rational(1, 3, 1, 6).unwrap();
assert_eq!(i8_result, (1, 2));
assert_eq!(i16_result, (1, 2));
assert_eq!(i32_result, (1, 2));
assert_eq!(i64_result, (1, 2));
let i8_mul = mul_i8_rational(2, 3, 3, 4).unwrap();
let i16_mul = mul_i16_rational(2, 3, 3, 4).unwrap();
let i32_mul = mul_i32_rational(2, 3, 3, 4).unwrap();
let i64_mul = mul_i64_rational(2, 3, 3, 4).unwrap();
assert_eq!(i8_mul, (1, 2));
assert_eq!(i16_mul, (1, 2));
assert_eq!(i32_mul, (1, 2));
assert_eq!(i64_mul, (1, 2));
}
#[test]
fn test_i128_rational_operations() {
let result = add_i128_rational(1, 3, 1, 6).unwrap();
assert_eq!(result, (1, 2));
let result = mul_i128_rational(2, 3, 3, 4).unwrap();
assert_eq!(result, (1, 2));
let result = div_i128_rational(1, 2, 1, 4).unwrap();
assert_eq!(result, (2, 1));
let result = sub_i128_rational(1, 2, 1, 3).unwrap();
assert_eq!(result, (1, 6));
}
#[test]
fn test_gcd_unsigned() {
assert_eq!(gcd_unsigned(12, 8), 4);
assert_eq!(gcd_unsigned(17, 13), 1);
assert_eq!(gcd_unsigned(100, 75), 25);
assert_eq!(gcd_unsigned(0, 5), 5);
assert_eq!(gcd_unsigned(0, 0), 1); }
}