【unitrix】 4.18 类型级二进制数加法实现解析(add.rs)
一、源码
这段代码实现了一个类型级别的二进制数加法系统,包括基本加法、带进位加法以及与其他数值类型的混合运算。
//! Type-level binary number addition implementation
//!
//! 本模块提供类型级别的二进制数加法运算,包括:
//! This module provides type-level binary number addition operations, including:
//! - 基本加法 (Basic addition)
//! - 带进位加法 (Addition with carry)
//! - 结果标准化处理 (Result standardization)
//! - 含类型级整数、小数与Var桥接的基本类型混合加法 (Mixed addition with typed integers, fixed-point and Var)use core::ops::Add;
use crate::number::{Z0, P1, N1, B0, B1, FixedPoint, Float, Var,NonZero, Primitive, TypedInt, Unsigned, Add1, Sub1, IfB0, IfB1, Shl1, Shr1
};// ==================== Addition With Carry ====================/// 带进位加法运算 (a + b + 1)
/// Addition with carry operation (a + b + 1)
/// 分Z0、P1、N1、B0、B1分别考虑。其中Z0在小数中使用
pub trait AddWithCarry<Rhs> {type Output;
}// ----- Z0 + All -----
// Z0 + I + 1=I + 1
impl<I: TypedInt + Add1> AddWithCarry<I> for Z0 {type Output = I::Output;
}// ----- P1 + All -----
// P1 + Z0 + 1 = 2
impl AddWithCarry<Z0> for P1 {type Output = B0<P1>;
}// P1 + P1 + 1 = 3
impl AddWithCarry<P1> for P1 {type Output = B1<P1>;
}// P1 + N1 + 1 = 1
impl AddWithCarry<N1> for P1 {type Output = P1;
}// P1 + B0<H> +1 =B0<H+1>
impl<H: NonZero + Add1<Output: IfB0>> AddWithCarry<B0<H>> for P1 {type Output = <H::Output as IfB0>::Output;
}// P1 + B1<H> +1 =B1<H+1>
impl<H: NonZero + Add1<Output: IfB1>> AddWithCarry<B1<H>> for P1 {type Output = <H::Output as IfB1>::Output;
}// ----- N1 + All -----
// N1 + I + 1 = I
impl<I: TypedInt> AddWithCarry<I> for N1 {type Output = I;
}// ----- B0 + All -----
// B0<H> + Z0 + 1 =B1<H>
impl<H: NonZero + IfB1> AddWithCarry<Z0> for B0<H> {type Output = <H as IfB1>::Output;
}// B0<H> + P1 + 1 =B0<H+1>
impl<H: NonZero + Add1<Output: IfB0>> AddWithCarry<P1> for B0<H> {type Output = <H::Output as IfB0>::Output;
}// B0<H> + N1 + 1 =B0<H>
impl<H: NonZero> AddWithCarry<N1> for B0<H> {type Output = Self;
}// B0<H1> + B0<H2> + 1= B1<H1+H2>
impl<H1: NonZero + Add<H2, Output: IfB1>, H2: NonZero> AddWithCarry<B0<H2>> for B0<H1> {type Output = <H1::Output as IfB1>::Output;
}// B0<H1> + B1<H2> + 1= B0<H1+H2+1>
impl<H1: NonZero + AddWithCarry<H2, Output: IfB0>, H2: NonZero> AddWithCarry<B1<H2>> for B0<H1> {type Output = <H1::Output as IfB0>::Output;
}// ----- B1 + All -----
// B1<H> + Z0 + 1 = B0<H+1>
impl<H: NonZero + Add1<Output: IfB0>> AddWithCarry<Z0> for B1<H> {type Output = <H::Output as IfB0>::Output;
}// B1<H> + P1 + 1 = B1<H+1>
impl<H: NonZero + Add1<Output: IfB1>> AddWithCarry<P1> for B1<H> {type Output = <H::Output as IfB1>::Output;
}// B1<H> + N1 + 1 = B1<H>
impl<H: NonZero + Add1> AddWithCarry<N1> for B1<H> {type Output = Self;
}// B1<H1> + B0<H2> + 1 = B0<H1+H2+1>
impl<H1: NonZero + AddWithCarry<H2, Output: IfB0>, H2: NonZero> AddWithCarry<B0<H2>> for B1<H1> {type Output = <H1::Output as IfB0>::Output;
}// B1<H1> + B1<H2> + 1 = B1<H1+H2+1>
impl<H1: NonZero + AddWithCarry<H2, Output: IfB1>, H2: NonZero> AddWithCarry<B1<H2>> for B1<H1> {type Output = <H1::Output as IfB1>::Output;
}// ==================== Operator Overloading ====================// ----- Z0 + All -----
// Z0 + I = I
impl<I: TypedInt> Add<I> for Z0 {type Output = I;#[inline(always)]fn add(self, rhs: I) -> Self::Output { rhs }
}// Z0 + FixedPoint = FixedPoint
impl<I: TypedInt, F: Unsigned> Add<FixedPoint<I, F>> for Z0 {type Output = FixedPoint<I, F>;#[inline(always)]fn add(self, rhs: FixedPoint<I, F>) -> Self::Output { rhs }
}// Z0 + Float = Float
impl<S, E> Add<Float<S, E>> for Z0 {type Output = Float<S, E>;#[inline(always)]fn add(self, rhs: Float<S, E>) -> Self::Output { rhs }
}// Z0 + Var<T> = Var<T>
impl<T: Primitive> Add<Var<T>> for Z0 {type Output = Var<T>;#[inline(always)]fn add(self, rhs: Var<T>) -> Self::Output { rhs }
}// ----- P1 + All -----
// P1 + I = I + 1
impl<I: TypedInt + Add1> Add<I> for P1 {type Output = I::Output;#[inline(always)]fn add(self, _: I) -> Self::Output { Default::default() }
}// P1 + FixedPoint
impl<I: TypedInt + Add1, F: Unsigned> Add<FixedPoint<I, F>> for P1 {type Output = FixedPoint<<I as Add1>::Output, F>;#[inline(always)]fn add(self, _: FixedPoint<I, F>) -> Self::Output { Default::default() }
}// P1 + Var<T>
impl<T: Primitive> Add<Var<T>> for P1
where Var<T>: Add + From<Self>,
{type Output = <Var<T> as Add>::Output;#[inline(always)]fn add(self, rhs: Var<T>) -> Self::Output { Var::<T>::from(Self) + rhs }
}// ----- N1 + All -----
// N1 + I = I + 1
impl<I: TypedInt + Sub1> Add<I> for N1 {type Output = I::Output;#[inline(always)]fn add(self, _: I) -> Self::Output { Default::default() }
}// N1 + FixedPoint = FixedPoint - 1
impl<I: TypedInt + Sub1, F: Unsigned> Add<FixedPoint<I, F>> for N1{type Output = FixedPoint<<I as Sub1>::Output, F>;#[inline(always)]fn add(self, _: FixedPoint<I, F>) -> Self::Output { Default::default() }
}// N1 + Var<T>
impl<T: Primitive> Add<Var<T>> for N1
where Var<T>: Add + From<Self>,
{type Output = <Var<T> as Add>::Output;#[inline(always)]fn add(self, rhs: Var<T>) -> Self::Output { Var::<T>::from(self) + rhs }
}// ----- B0 + All -----
// B0<H> + Z0 = B0<H>
impl<H: NonZero> Add<Z0> for B0<H> {type Output = Self;#[inline(always)]fn add(self, _: Z0) -> Self::Output { self }
}// B0<H> + P1 = B0<H> + 1
impl<H: NonZero> Add<P1> for B0<H>
where B0<H>: Add1,
{type Output = <B0<H> as Add1>::Output;#[inline(always)]fn add(self, _: P1) -> Self::Output { Default::default() }
}// B0<H> + N1 = B0<H> - 1
impl<H: NonZero> Add<N1> for B0<H>
whereB0<H>: Sub1,
{type Output = <B0<H> as Sub1>::Output;#[inline(always)]fn add(self, _: N1) -> Self::Output { Default::default() }
}// B0<H1> + B0<H2> = B0<H1+H2>
impl<H1: NonZero + Add<H2, Output: IfB0>, H2: NonZero> Add<B0<H2>> for B0<H1> {type Output = <H1::Output as IfB0>::Output;#[inline(always)]fn add(self, _: B0<H2>) -> Self::Output { Default::default() }
}// B0<H1> + B1<H2> = B1<H1+H2>
impl<H1: NonZero + Add<H2, Output: IfB1>, H2: NonZero> Add<B1<H2>> for B0<H1> {type Output = <H1::Output as IfB1>::Output;#[inline(always)]fn add(self, _: B1<H2>) -> Self::Output { Default::default() }
}// B0<H> + FixedPoint<I, F> = FixedPoint<I + B0<H>, F>
impl<H: NonZero, I: TypedInt + Add<Self>, F: Unsigned> Add<FixedPoint<I, F>> for B0<H>{type Output = FixedPoint<<I as Add<Self>>::Output, F>;#[inline(always)]fn add(self, _: FixedPoint<I, F>) -> Self::Output { Default::default() }
}// B0<H> + Var<T>
impl< H: NonZero, T: Primitive> Add<Var<T>> for B0<H>
where Var<T>: Add + From<Self>,
{type Output = <Var<T> as Add>::Output;#[inline(always)]fn add(self, rhs: Var<T>) -> Self::Output { Var::<T>::from(self) + rhs }
}// ----- B1 + All -----
// B1<H> + Z0 = B1<H>
impl<H: NonZero> Add<Z0> for B1<H> {type Output = Self;#[inline(always)]fn add(self, _: Z0) -> Self::Output { self }
}// B1<H> + P1 = B1<H> + 1
impl<H: NonZero> Add<P1> for B1<H>
whereB1<H>: Add1,
{type Output = <B1<H> as Add1>::Output;#[inline(always)]fn add(self, _: P1) -> Self::Output { Default::default() }
}// B1<H> + N1 = B1<H> - 1
impl<H: NonZero> Add<N1> for B1<H>
where B1<H>: Sub1,
{type Output = <B1<H> as Sub1>::Output;#[inline(always)]fn add(self, _: N1) -> Self::Output { Default::default() }
}// B1<H1> + B0<H2> = B1<H1+H2>
impl<H1: NonZero + Add<H2, Output: IfB1>, H2: NonZero> Add<B0<H2>> for B1<H1> {type Output = <H1::Output as IfB1>::Output;#[inline(always)]fn add(self, _: B0<H2>) -> Self::Output { Default::default() }
}// B1<H1> + B1<H2> = B0<H1+H2+1>
impl<H1: NonZero + AddWithCarry<H2, Output: IfB0>, H2: NonZero> Add<B1<H2>> for B1<H1> {type Output = <H1::Output as IfB0>::Output;#[inline(always)]fn add(self, _: B1<H2>) -> Self::Output { Default::default() }
}// B1<H> + FixedPoint<I, F> = FixedPoint<I + B1<H>, F>
impl< H: NonZero, I: TypedInt + Add<Self>, F: Unsigned> Add<FixedPoint<I, F>> for B1<H>{type Output = FixedPoint<<I as Add<Self>>::Output, F>;#[inline(always)]fn add(self, _: FixedPoint<I, F>) -> Self::Output { Default::default() }
}// B1<H> + Var<T>
impl<T: Primitive, H: NonZero> Add<Var<T>> for B1<H>
where Var<T>: Add + From<Self>,
{type Output = <Var<T> as Add>::Output;#[inline(always)]fn add(self, rhs: Var<T>) -> Self::Output { Var::<T>::from(self) + rhs }
}// ----- FixedPoint + All -----
// FixedPoint<I, F> + I2 = FixedPoint<I + I2, F>
impl<I: TypedInt + Add<I2>, F: Unsigned, I2: TypedInt> Add<I2> for FixedPoint<I, F>{type Output = FixedPoint<<I as Add<I2>>::Output, F>;#[inline(always)]fn add(self, _: I2) -> Self::Output { Default::default() }
}// FixedPoint<I1, F1> + FixedPoint<I2, F2>,F1为Z0、P1、B0、B1时分别计算
// F1=Z0时...
impl<I1: TypedInt + Add<I2>,I2: TypedInt, F2: Unsigned> Add<FixedPoint<I2, F2>> for FixedPoint<I1, Z0>{type Output = FixedPoint<<I1 as Add<I2>>::Output, F2>;#[inline(always)]fn add(self, _: FixedPoint<I2, F2>) -> Self::Output { Default::default() }
}// F1=P1时...
// F2=Z0
impl<I1: TypedInt + Add<I2>,I2: TypedInt> Add<FixedPoint<I2, Z0>> for FixedPoint<I1, P1>{type Output = FixedPoint<I1::Output, P1>;#[inline(always)]fn add(self, _: FixedPoint<I2, Z0>) -> Self::Output { Default::default() }
}
// F2=P1
impl<I1: TypedInt + AddWithCarry<I2>,I2: TypedInt> Add<FixedPoint<I2, P1>> for FixedPoint<I1, P1>{type Output = FixedPoint<I1::Output, Z0>;#[inline(always)]fn add(self, _: FixedPoint<I2, P1>) -> Self::Output { Default::default() }
}
// F2=B0<L>
impl<I1: TypedInt + Add<I2>,I2: TypedInt, L: Unsigned + NonZero> Add<FixedPoint<I2, B0<L>>> for FixedPoint<I1, P1>{type Output = FixedPoint<I1::Output, B1<L>>;#[inline(always)]fn add(self, _: FixedPoint<I2, B0<L>>) -> Self::Output { Default::default() }
}// F2=B1<L>
impl<I1: TypedInt + AddWithCarry<I2>,I2: TypedInt, L: Unsigned + NonZero> Add<FixedPoint<I2, B1<L>>> for FixedPoint<I1, P1>{type Output = FixedPoint<I1::Output, B0<L>>;#[inline(always)]fn add(self, _: FixedPoint<I2, B1<L>>) -> Self::Output { Default::default() }
}// F1=B0<L>时...
// F2=Z0
impl<I1: TypedInt + Add<I2>,I2: TypedInt, L: Unsigned + NonZero> Add<FixedPoint<I2, Z0>> for FixedPoint<I1, B0<L>>{type Output = FixedPoint<I1::Output, B0<L>>;#[inline(always)]fn add(self, _: FixedPoint<I2, Z0>) -> Self::Output { Default::default() }
}
// F2=P1
impl<I1: TypedInt + Add<I2>,I2: TypedInt, L: Unsigned + NonZero> Add<FixedPoint<I2, P1>> for FixedPoint<I1, B0<L>>{type Output = FixedPoint<I1::Output, B1<L>>;#[inline(always)]fn add(self, _: FixedPoint<I2, P1>) -> Self::Output { Default::default() }
}
// F2=B0<L>
impl<I1: TypedInt + IfB0, I2: TypedInt + IfB0, L1: Unsigned + NonZero, L2: Unsigned + NonZero> Add<FixedPoint<I2, B0<L2>>> for FixedPoint<I1, B0<L1>>
whereFixedPoint<I1::Output, L1>: Add<FixedPoint<I2::Output, L2>>,<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output: Shr1,<<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output as Shr1>::Output: Default,
{type Output = <<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output as Shr1>::Output;#[inline(always)]fn add(self, _: FixedPoint<I2, B0<L2>>) -> Self::Output { Default::default() }
}// F2=B1<L>
impl<I1: TypedInt + IfB0, I2: TypedInt + IfB1, L1: Unsigned + NonZero, L2: Unsigned + NonZero> Add<FixedPoint<I2, B1<L2>>> for FixedPoint<I1, B0<L1>>
whereFixedPoint<I1::Output, L1>: Add<FixedPoint<I2::Output, L2>>,<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output: Shr1,<<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output as Shr1>::Output: Default,
{type Output = <<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output as Shr1>::Output;#[inline(always)]fn add(self, _: FixedPoint<I2, B1<L2>>) -> Self::Output { Default::default() }
}// F1=B1<L>时...
// F2=Z0
impl<I1: TypedInt + Add<I2>, I2: TypedInt, L: Unsigned + NonZero> Add<FixedPoint<I2, Z0>> for FixedPoint<I1, B1<L>>{type Output = FixedPoint<I1::Output, B1<L>>;#[inline(always)]fn add(self, _: FixedPoint<I2, Z0>) -> Self::Output { Default::default() }
}
// F2=P1
impl<I1: TypedInt + AddWithCarry<I2>, I2: TypedInt, L: Unsigned + NonZero> Add<FixedPoint<I2, P1>> for FixedPoint<I1, B1<L>>{type Output = FixedPoint<I1::Output, B0<L>>;#[inline(always)]fn add(self, _: FixedPoint<I2, P1>) -> Self::Output { Default::default() }
}
// F2=B0<L>
impl<I1: TypedInt + IfB1, I2: TypedInt + IfB0, L1: Unsigned + NonZero, L2: Unsigned + NonZero> Add<FixedPoint<I2, B0<L2>>> for FixedPoint<I1, B1<L1>>
whereFixedPoint<I1::Output, L1>: Add<FixedPoint<I2::Output, L2>>,<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output: Shr1,<<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output as Shr1>::Output: Default,
{type Output = <<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output as Shr1>::Output;#[inline(always)]fn add(self, _: FixedPoint<I2, B0<L2>>) -> Self::Output { Default::default() }
}// F2=B1<L>
impl<I1: TypedInt + IfB1, I2: TypedInt + IfB1, L1: Unsigned + NonZero, L2: Unsigned + NonZero> Add<FixedPoint<I2, B1<L2>>> for FixedPoint<I1, B1<L1>>
whereFixedPoint<I1::Output, L1>: Add<FixedPoint<I2::Output, L2>>,<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output: Shr1,<<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output as Shr1>::Output: Default,
{type Output = <<FixedPoint<I1::Output, L1> as Add<FixedPoint<I2::Output, L2>>>::Output as Shr1>::Output;#[inline(always)]fn add(self, _: FixedPoint<I2, B1<L2>>) -> Self::Output { Default::default() }
}// ----- Var<T> Operations -----
impl<T: Primitive, I: TypedInt> Add<I> for Var<T>
where Var<T>: From<I> + Add,
{type Output = <Var<T> as Add>::Output;fn add(self, rhs: I) -> Self::Output { self + Var::<T>::from(rhs)}
}
//?????
impl<T: Primitive> Add for Var<T> {type Output = Self;#[inline(always)]fn add(self, rhs: Self) -> Self::Output { Var(self.0 + rhs.0) }
}#[cfg(test)]
mod tests {use crate::number::*;#[test]fn test_z0_addition() {assert_eq!(Z0 + Z0, Z0);assert_eq!(Z0 + P1, P1);assert_eq!(Z0 + N1, N1);assert_eq!(Z0 + B0::<P1>::default(), B0::<P1>::default());assert_eq!(Z0 + B1::<P1>::default(), B1::<P1>::default());}#[test]fn test_p1_addition() {assert_eq!(P1 + Z0, P1);assert_eq!(P1 + P1, B0::<P1>::default());assert_eq!(P1 + N1, Z0);assert_eq!(P1 + B0::<P1>::default(), B1::<P1>::default());assert_eq!(P1 + B1::<P1>::default(), B0::<B0::<P1>>::default());}#[test]fn test_n1_addition() {assert_eq!(N1 + Z0, N1);assert_eq!(N1 + P1, Z0);assert_eq!(N1 + N1, B0::<N1>::default());assert_eq!(N1 + B0::<P1>::default(), P1);assert_eq!(N1 + B1::<P1>::default(), B0::<P1>::default());}#[test]fn test_b0_addition() {let b0_p1 = B0::<P1>::default();let b1_p1 = B1::<P1>::default();assert_eq!(b0_p1 + Z0, b0_p1);assert_eq!(b0_p1 + P1, B1::<P1>::default());assert_eq!(b0_p1 + N1, P1);assert_eq!(b0_p1 + b0_p1, B0::<B0::<P1>>::default());assert_eq!(b0_p1 + b1_p1, B1::<B0::<P1>>::default());}#[test]fn test_b1_addition() {let b1_p1 = B1::<P1>::default();let b0_p1 = B0::<P1>::default();assert_eq!(b1_p1 + Z0, b1_p1);assert_eq!(b1_p1 + P1, B0::<B0::<P1>>::default());assert_eq!(b1_p1 + N1, B0::<P1>::default());assert_eq!(b1_p1 + b0_p1, B1::<B0::<P1>>::default());assert_eq!(b1_p1 + b1_p1, B0::<B1::<P1>>::default());}#[test]fn test_fixed_point_addition() {let fp = FixedPoint::<P1, P1>::default();assert_eq!(Z0 + fp, fp);assert_eq!(P1 + fp, FixedPoint::<B0::<P1>, P1>::default());assert_eq!(N1 + fp, FixedPoint::<Z0, P1>::default());}#[test]fn test_var_addition() {let var1 = Var::<i32>::from(1);let var2 = Var::<i32>::from(2);assert_eq!(Z0 + var1.clone(), var1);assert_eq!(P1 + var1.clone(), Var::from(2));assert_eq!(N1 + var1.clone(), Var::from(0));assert_eq!(var1 + var2, Var::from(3));}#[test]fn test_add_with_carry() {assert_eq!(<P1 as AddWithCarry<P1>>::Output::default(), B1::<P1>::default());assert_eq!(<P1 as AddWithCarry<N1>>::Output::default(), P1::default());assert_eq!(<B0::<P1> as AddWithCarry<B1::<P1>>>::Output::default(), B0::<B1::<P1>>::default());assert_eq!(<B1::<P1> as AddWithCarry<B0::<P1>>>::Output::default(), B0::<B1::<P1>>::default());}#[test]fn test_nested_binary_addition() {let b0_b1_p1 = B0::<B1::<P1>>::default();let b1_b0_p1 = B1::<B0::<P1>>::default();assert_eq!(b0_b1_p1 + b0_b1_p1, B0::<B0::<B1::<P1>>>::default());assert_eq!(b1_b0_p1 + b1_b0_p1, B0::<B1::<B0::<P1>>>::default());assert_eq!(b0_b1_p1 + b1_b0_p1, B1::<B1::<B0::<P1>>>::default());}#[test]fn test_deeply_nested_addition() {let b0_b0_b1_p1 = B0::<B0::<B1::<P1>>>::default();let b1_b1_b0_p1 = B1::<B1::<B0::<P1>>>::default();assert_eq!(b0_b0_b1_p1 + b1_b1_b0_p1, B1::<B1<B1<B0<P1>>>>::default());}#[test]fn test_fixed_point_precision_combinations() {// Different fractional precisionslet fp1 = FixedPoint::<P1, B0::<P1>>::default();let fp2 = FixedPoint::<P1, B1::<P1>>::default();assert_eq!(fp1 + fp2, FixedPoint::<B1::<P1>, Z0>::default());// Larger integer partslet fp3 = FixedPoint::<B0::<B1::<P1>>, P1>::default();let fp4 = FixedPoint::<B1::<B0::<P1>>, P1>::default();assert_eq!(fp3 + fp4, FixedPoint::<B0<B0<B1<P1>>>, Z0>::default());}#[test]fn test_var_mixed_operations() {// Test with different primitive typeslet var_i32 = Var::<i32>::from(5);let var_f64 = Var::<f64>::from(3.5);assert_eq!(var_i32 + P1, Var::<i32>::from(6));assert_eq!(var_f64 + N1, Var::<f64>::from(2.5));// Test with larger valueslet big_var = Var::<i64>::from(i64::MAX - 1);assert_eq!(big_var + P1, Var::<i64>::from(i64::MAX));}#[test]fn test_edge_cases() {// Maximum nested binary numbertype MaxNested = B1::<B1::<B1::<B1::<P1>>>>;let max_val = MaxNested::default();assert_eq!(max_val + Z0, max_val);// Minimum value testslet min_fp = FixedPoint::<N1, Z0>::default();assert_eq!(min_fp + P1, FixedPoint::<Z0, Z0>::default());}#[test]fn test_add_with_carry_edge_cases() {// Test carry propagationassert_eq!(<B1::<B1::<P1>> as AddWithCarry<B1::<B1::<P1>>>>::Output::default(),B1::<B1::<B1::<P1>>>::default());// Test with maximum valuestype MaxCarry = B1::<B1::<B1::<P1>>>;assert_eq!(<MaxCarry as AddWithCarry<MaxCarry>>::Output::default(),B1::<B1::<B1::<B1::<P1>>>>::default());}#[test]fn test_fixed_point_overflow() {// Test behavior when integer part would overflowlet max_fp = FixedPoint::<B1::<B1::<P1>>, Z0>::default();let one = FixedPoint::<P1, Z0>::default();assert_eq!(max_fp + one, FixedPoint::<B0::<B0::<B0::<P1>>>, Z0>::default());}
}
二、核心概念
- 类型表示
-
Z0: 表示零
-
P1: 表示+1
-
N1: 表示-1
-
B0: 表示二进制数0后跟更高位H
-
B1: 表示二进制数1后跟更高位H
- 主要特性
-
AddWithCarry: 带进位加法特征(a + b + 1)
-
Add: 标准加法特征(a + b)
三、带进位加法实现
AddWithCarry trait 定义了所有可能的带进位加法组合:
- Z0 + 任何类型:
- 结果等于另一个数加1 (I + 1)
- P1 + 各种类型:
-
P1 + Z0 + 1 = 2 (表示为B0)
-
P1 + P1 + 1 = 3 (表示为B1)
-
P1 + N1 + 1 = 1 (P1)
-
与B0/B1的组合会产生进位传播
- N1 + 任何类型:
- 结果等于另一个数本身(因为-1 + 0 +1 = 0)
- B0/B1 + 各种类型:
-
处理二进制数的进位传播
-
根据输入类型的不同产生不同的输出类型
四、标准加法实现
标准加法通过Rust的Add trait实现,覆盖了所有类型组合:
- 基本类型加法:
-
Z0 + I = I (零加任何数等于该数)
-
P1 + I = I + 1
-
N1 + I = I - 1
- 二进制数加法:
-
B0 + B0 = B0<H1+H2>
-
B0 + B1 = B1<H1+H2>
-
B1 + B1 = B0<H1+H2+1> (产生进位)
- 定点数加法:
-
处理整数部分和小数部分的不同组合
-
根据小数部分的类型(P1/Z0/B0/B1)进行不同的计算
- 变量类型(Var)加法:
-
支持与各种类型相加
-
最终转换为运行时计算
五、定点数加法细节
定点数加法(FixedPoint<I, F>)是最复杂的部分,需要同时处理:
-
整数部分(I)的加法
-
小数部分(F)的加法
-
不同小数精度的处理:
-
Z0: 无小数
-
P1: 0.5
-
B0: 0.xxx形式
-
B1: 0.1xxx形式
对于不同小数精度的组合,代码中实现了专门的加法规则,确保结果正确。
六、测试用例
测试覆盖了:
-
基本类型加法
-
二进制数加法(包括嵌套情况)
-
定点数加法
-
变量类型加法
-
边界情况(最大值、最小值)
-
进位传播
七、设计亮点
-
类型安全: 所有运算在编译期确定,无运行时开销
-
扩展性: 可以轻松添加新的数值类型
-
组合性: 支持不同类型之间的混合运算
-
精确控制: 特别是定点数运算可以精确控制小数精度
这个实现展示了Rust类型系统的强大能力,通过类型级编程实现了复杂的数值运算系统。