1、平衡三进制乘法表

        前面写了平衡三进制的加法器,这个乘法器是在这基础上的,没看过的可以回去看看,说到乘法器还是要参考前苏联的资料的,平衡三进制的乘法也是很方便的,在平衡三进制基础中有详细讲过,下图就是资料:

        也就是有(-1/0/1)这三相数互相相乘,结果得到的还是(-1/0/1),所以是很方便的,你认真看这乘法表其实就是逻辑表中的同或门(零乘任何数都为0,然后1*1与T*T结果都为1、最后是T*1或是1*T结果都为T),所以平衡三进制同或门等同于乘法表。


2、平衡三进制2位乘法器

        这平衡三进制的乘法器,与二进制结构差不太多,也就是从低位到高位,依次相乘后相加与我们人类的计算一样,只过用一个用的是二进制,另一个用的是平衡三进制,原理结构图,如下所示:

        用上面的思路,即AB*CD,得AC*100+10*(AD+BC)+BD,这三部分在不同的位置上,同或门完成的是AC相乘的结果,就是1位相乘的结果,它结果就是1trit,所以很有优势,也是只要半加器相加就可以,这样就可以写出,如下代码:

// **加和(TSUM)逻辑表 当为TT、01、10时出1,当为11、0T、T0时出T,其余为0 此门用于半加器的加和位处理 **
const TSUM:[[u8; 3];3]= [
    [0, 1, 2],
    [1, 2, 0],
    [2, 0, 1],
];
// **共识(TCONS)逻辑表 双T出T、双1出1、其余为0 此门用于半加器的进位处理 **
const TCONS:[[u8; 3];3]= [
    [0, 0, 0],
    [0, 1, 0],
    [0, 0, 2],
];
// **调和(TANY)逻辑表 当为TT、0T、T0时出T,当为11、01、10时出1,其余为0 此门用于全加器进位处理 **
const TANY:[[u8; 3];3]= [
    [0, 1, 2],
    [1, 1, 0],
    [2, 0, 2],
];
// **同或门(TXNOR)逻辑表 双T及双1出1、1T及T1出T、其余为0 此门相当于乘法表用于相乘处理 **
pub const TXNOR:[[u8; 3];3]= [
    [0, 0, 0],
    [0, 1, 2],
    [0, 2, 1],
];

/// 半加器:返回 (sum, carry)
pub fn ternary_half_adder(a: u8, b: u8) -> (u8, u8) {
    let sum = TSUM[a as usize][b as usize];// 和
    let carry=TCONS[a as usize][b as usize];// 进位;
    (sum, carry)
}
/// 全加器:基于半加器实现
pub fn ternary_full_adder(a: u8, b: u8, c_in: u8) -> (u8, u8) {
    //2个平衡三进制半加器及1个平衡三进制调和门,组成一个平衡三进制全加器
    let (num,c1_in)=ternary_half_adder(a,b);
    let (sum,c2_in)=ternary_half_adder(num,c_in);
    let carry=TANY[c1_in as usize][c2_in as usize];//两个进位数合成一个进位数;
    (sum, carry)
}
/// 2位乘法器
pub fn ternary_2trit_mul(a: u8, b: u8, c:u8, d:u8) -> (u8, u8,u8,u8) {
    //2n个平衡三进制同或门及n个平衡三进制半加器,组成一个平衡三进制乘法器
    let ac=TXNOR[a as usize][c as usize];
    let ad=TXNOR[a as usize][d as usize];
    let bc=TXNOR[b as usize][c as usize];
    let bd=TXNOR[b as usize][d as usize];

    let (num,carry)=ternary_half_adder(ad, bc);
    let (num2,carry2)=ternary_half_adder(ac, carry);
    (carry2,num2,num,bd)
}

///多位三进制加法器基础,输入两个的三进制向量,返回加法结果向量和最终进位
pub fn ternary_stackadder_base(mut stack1: Vec<u8>,mut stack2: Vec<u8>,carry_in: u8)-> (Vec<u8>, u8){
    let mut result:Vec<u8> = Vec::new();//存储和
    let mut c_in:u8=carry_in;
    
    //Rust标准库中Vec,天然支持后进先出(LIFO),用栈协同弹出,倒序遍历, 支持不同长度
    while !stack1.is_empty() || !stack2.is_empty() {
        let v1 = stack1.pop().unwrap_or(0);
        let v2 = stack2.pop().unwrap_or(0);
 
        let (s_out, next_carry) =ternary_full_adder(v1, v2, c_in);
        result.push(s_out);//存结果
        c_in=next_carry;//进位传递
    }
    //result.push(c_in);可选,最高位溢出推入
    result.reverse(); // 反转,从高位到低位排列
    (result, c_in)
}
 
//多位三进制加法器
pub fn ternary_stack_adder(stack1: Vec<u8>,stack2: Vec<u8>) -> Vec<u8> {
    let (mut result, carry) = ternary_stackadder_base(stack1,stack2, 0);
    result.insert(0, carry);
    result
}
 
fn main() {
    println!("结果{:?}",ternary_2trit_mul(1, 2, 2, 0));//1T(2)*T0(-3)=0T10(-9+3=-6)
    println!("结果{:?}",ternary_2trit_mul(2, 2, 1, 2));//TT(-4)*1T(2)=0T01(-9+1=-8)
    println!("结果{:?}",ternary_2trit_mul(1, 1, 1, 1));//11(4)*11(4)=1TT1(27-9-3+1=16)
}

结果正确。


3、平衡三进制多位乘法器

        在这基础上实现多位乘法器,也是很简单的,可以用经典的“列乘法”逻辑,也就是被乘数是固定的,每个乘数单独相乘,得到多个部分积,最后移位后相加即可,详情请看计算机组成原理(九):乘法器,借用一下思路,如下所示:

  A = 1101  (13 in decimal)
× B = 1011  (11 in decimal)
--------------
      1101   (部分积1)
+    1101    (部分积2)
+   0000     (部分积3)
+  1101      (部分积4)
--------------
  10001111   (143 in decimal)

也就分别得到各个部分积,这也可用于平衡三进制,得代码如下所示:

// **全加器和(TFULLSUM) 逻辑表**
const TFULLSUM:[[[u8; 3];3];3] = [
    [
        [0, 1, 2],
        [1, 2, 0],
        [2, 0, 1],
    ],
    [
        [1, 2, 0],
        [2, 0, 1],
        [0, 1, 2],
    ],
    [
        [2, 0, 1],
        [0, 1, 2],
        [1, 2, 0],
    ],
];
// **全加器进位(TFULLCONS) 逻辑表**
const TFULLCONS:[[[u8; 3];3];3] = [
    [
        [0, 0, 0],
        [0, 1, 0],
        [0, 0, 2],
    ],
    [
        [0, 1, 0],
        [1, 1, 0],
        [0, 0, 0],
    ],
    [
        [0, 0, 2],
        [0, 0, 0],
        [2, 0, 2],
    ],
];
// **同或门(TXNOR)逻辑表 双T及双1出1、1T及T1出T、其余为0 此门相当于乘法表用于相乘处理 **
pub const TXNOR:[[u8; 3];3]= [
    [0, 0, 0],
    [0, 1, 2],
    [0, 2, 1],
];

/// 全加器:基于三维数组实现
pub fn ternary_full_adder(a: u8, b: u8, c_in: u8) -> (u8, u8) {
    let sum =TFULLSUM[a as usize][b as usize][c_in as usize];// 和
    let carry=TFULLCONS[a as usize][b as usize][c_in as usize];// 进位
    (sum, carry)
}
///多位三进制加法器基础,输入两个的三进制向量,返回加法结果向量和最终进位
pub fn ternary_stack_adder(mut stack1: Vec<u8>,mut stack2: Vec<u8>)-> Vec<u8>{
    let mut result:Vec<u8> = Vec::new();//存储和
    let mut c_in:u8=0;
    
    //Rust标准库中Vec,天然支持后进先出(LIFO),用栈协同弹出,倒序遍历, 支持不同长度
    while !stack1.is_empty() || !stack2.is_empty() {
        let v1 = stack1.pop().unwrap_or(0);
        let v2 = stack2.pop().unwrap_or(0);
 
        let (s_out, next_carry) =ternary_full_adder(v1, v2, c_in);
        result.push(s_out);//存结果
        c_in=next_carry;//进位传递
    }
    result.push(c_in);//推入最高位
    result.reverse(); // 反转,从高位到低位排列
    result
}

///多位三进制乘法器基础
pub fn ternary_mul_base(stack1: Vec<u8>, stack2: Vec<u8>)-> Vec<u8>{
    let mut partials: Vec<Vec<u8>> =  Vec::new();
    let mut shift = 0;
    //将 stack2 看作乘数,从低位到高位
    for &m2 in stack2.iter().rev(){
        //将 stack1 看作被乘数,固定不动
        let mut partial: Vec<u8> = stack1.iter().map(|&m1| TXNOR[m1 as usize][m2 as usize]).collect();
        // 在尾部精确补0
        partial.extend(vec![0; shift]);
        shift += 1;
        partials.push(partial);
    }
    //累加所有偏移乘积
    let mut result = vec![0];
    for partial in partials {
        result = ternary_stack_adder(result, partial);
    }
    result
}

fn main() {
    let stack1=vec![1,1,0,1];
    let stack2=vec![1,0,1,1];
    let re=ternary_mul_base(stack1,stack2);
    print!("{:?}",re);
}

结果正确,1101(十进制31)*1011(十进制31)=1TTT0111(十进制1147)。


4、平衡三进制偏积表乘法器

        从上面可以得知,它是用各个部分积累计相加得到结果的,也就是说只要得到,各个偏积就能有结果,其中N位与N位相乘最大结果位数是2N,比如:

A=1101(被乘数)        B=1011(乘数)

1101 * 1=1101
1101 * 1=1101
1101 * 0=0000
1101 * 1=1101

所以,在平衡三进制中,有任何数0乘都得0,任何数乘1等于它本身,任何数乘T(-1)等于相反数,这样可构建出偏积表,有没有注意上多个部分积,只有1101与0000,它是二进制的,而对于平衡三进制它的结果有三种,即:0000、1101、2202,这个就是偏积表,用被乘数形成偏积表,乘数当成下标来调用偏积表,然后移位后相加就可以得到最后的结果,长的当被乘数好,这样算的快,这个版本比上面的版本好,代码如下所示:

// **全加器和(TFULLSUM) 逻辑表**
const TFULLSUM:[[[u8; 3];3];3] = [
    [
        [0, 1, 2],
        [1, 2, 0],
        [2, 0, 1],
    ],
    [
        [1, 2, 0],
        [2, 0, 1],
        [0, 1, 2],
    ],
    [
        [2, 0, 1],
        [0, 1, 2],
        [1, 2, 0],
    ],
];
// **全加器进位(TFULLCONS) 逻辑表**
const TFULLCONS:[[[u8; 3];3];3] = [
    [
        [0, 0, 0],
        [0, 1, 0],
        [0, 0, 2],
    ],
    [
        [0, 1, 0],
        [1, 1, 0],
        [0, 0, 0],
    ],
    [
        [0, 0, 2],
        [0, 0, 0],
        [2, 0, 2],
    ],
];
// **非门(TNEG)逻辑表 输入T,输出1;输入0,输出0;输入1,输出T;**
const TNEG:[u8; 3]= [0, 2, 1];

/// 全加器:基于三维数组实现
pub fn ternary_full_adder(a: u8, b: u8, c_in: u8) -> (u8, u8) {
    let sum =TFULLSUM[a as usize][b as usize][c_in as usize];// 和
    let carry=TFULLCONS[a as usize][b as usize][c_in as usize];// 进位
    (sum, carry)
}
///多位三进制加法器基础,输入两个的三进制向量,返回加法结果向量和最终进位
pub fn ternary_stack_adder(mut stack1: Vec<u8>,mut stack2: Vec<u8>)-> Vec<u8>{
    let mut result:Vec<u8> = Vec::new();//存储和
    let mut c_in:u8=0;
    
    //Rust标准库中Vec,天然支持后进先出(LIFO),用栈协同弹出,倒序遍历, 支持不同长度
    while !stack1.is_empty() || !stack2.is_empty() {
        let v1 = stack1.pop().unwrap_or(0);
        let v2 = stack2.pop().unwrap_or(0);
 
        let (s_out, next_carry) =ternary_full_adder(v1, v2, c_in);
        result.push(s_out);//存结果
        c_in=next_carry;//进位传递
    }
    result.push(c_in);//推入最高位
    result.reverse(); // 反转,从高位到低位排列
    result
}

///多位三进制乘法器基础
pub fn ternary_mul_base(stack1: Vec<u8>, stack2: Vec<u8>)-> Vec<u8>{
    let partial_t: Vec<u8> = stack1.iter().map(|&m| TNEG[m as usize]).collect();
    // 构建偏积表:分别是乘以 0, 1, T 的情况
    let partials = vec![
        vec![0; stack1.len()], //0乘任何数,都得0
        stack1.clone(),        //任何数乘1,等于它本身
        partial_t,             //任何数乘T(-1)等于相反数
    ];
    let mut result: Vec<u8> = vec![0];
    for (shift, &m2) in stack2.iter().rev().enumerate() {
        let mut part = partials[m2 as usize].clone();//用偏积表,m2当成下标,出可变副本
        part.resize(part.len() + shift, 0); // 更高效的偏移,低位补 0
        result = ternary_stack_adder(result, part);//加入当前部分积
    }
    result
}

fn main() {
    let stack1=vec![1,1,0,1];
    let stack2=vec![1,0,1,1];
    let re=ternary_mul_base(stack1,stack2);
    print!("{:?}",re);
}

结果正确。


5、平衡三进制的逻辑比较器

        平衡三进制的减法,即A-B=A+(-B),减去一个数,相当于加上它的相反数,平衡三进制的比较逻辑需基于三值逻辑运算,核心是通过减法运算后对结果进行判断,计算两个数的差值(a - b),如下所示:

判断差值符号:
如果差值为 0,输出 0(两数相等)。
如果差值为正(即 a > b),输出 +1(第一个数大于第二个数)。
如果差值为负(即 a < b),输出 -1(第一个数小于第二个数)。

用两个平衡三进制数相减后,最高有效位,即最高位从左数起不为0,这样就可以判断两者的大小,其中的非零门可判断一个数的正负值,代码如下所示:

// **非门(TNEG)逻辑表 输入T,输出1;输入0,输出0;输入1,输出T;**
const TNEG:[u8; 3]= [0, 2, 1];
// **非零门(TPOZ)逻辑表 当为T1、0T、T0、TT时出T,当为1T、01、10、11时出1,双0出0 此门用于检测其最高位的正负性,出T为负数,出1为正数,出0则0 **
pub const TPOZ:[[u8; 3];3]= [
    [0, 1, 2],
    [1, 1, 1],
    [2, 2, 2],
];
// **全加器和(TFULLSUM) 逻辑表**
const TFULLSUM:[[[u8; 3];3];3] = [
    [
        [0, 1, 2],
        [1, 2, 0],
        [2, 0, 1],
    ],
    [
        [1, 2, 0],
        [2, 0, 1],
        [0, 1, 2],
    ],
    [
        [2, 0, 1],
        [0, 1, 2],
        [1, 2, 0],
    ],
];
// **全加器进位(TFULLCONS) 逻辑表**
const TFULLCONS:[[[u8; 3];3];3] = [
    [
        [0, 0, 0],
        [0, 1, 0],
        [0, 0, 2],
    ],
    [
        [0, 1, 0],
        [1, 1, 0],
        [0, 0, 0],
    ],
    [
        [0, 0, 2],
        [0, 0, 0],
        [2, 0, 2],
    ],
];
  
/// 全加器:基于三维数组实现
pub fn ternary_full_adder(a: u8, b: u8, c_in: u8) -> (u8, u8) {
    let sum =TFULLSUM[a as usize][b as usize][c_in as usize];// 和
    let carry=TFULLCONS[a as usize][b as usize][c_in as usize];// 进位
    (sum, carry)
}
 
///多位三进制加减器基础,输入两个的三进制向量,返回加法结果向量和最终进位
fn ternary_stack_base(mut stack1: Vec<u8>,mut stack2: Vec<u8>,is_sub:bool)-> Vec<u8>{
    let mut result:Vec<u8> = Vec::new();//存储和
    let mut c_in:u8=0;
    
    //Rust标准库中Vec,天然支持后进先出(LIFO),用栈协同弹出,倒序遍历, 支持不同长度
    while !stack1.is_empty() || !stack2.is_empty() {
        let v1 = stack1.pop().unwrap_or(0);
        let v2 = stack2.pop().unwrap_or(0);
        let v3=if is_sub {TNEG[v2 as usize]}else{v2};
 
        let (s_out, next_carry) =ternary_full_adder(v1, v3, c_in);
        result.push(s_out);//存结果
        c_in=next_carry;//进位传递
    }
    if c_in!=0{
        result.push(c_in);//推入最高位
    }
    result.reverse(); // 反转,从高位到低位排列
    result
}
 
///多位三进制加法器
pub fn ternary_stack_adder(stack1: Vec<u8>,stack2: Vec<u8>)-> Vec<u8>{
    ternary_stack_base(stack1, stack2, false)
}
///多位三进制减法器
pub fn ternary_stack_sub(stack1: Vec<u8>,stack2: Vec<u8>)-> Vec<u8>{
    ternary_stack_base(stack1, stack2, true)
}
 
///多位三进制乘法器基础
pub fn ternary_mul_base(stack1: Vec<u8>, stack2: Vec<u8>)-> Vec<u8>{
    // 构建偏积表:分别是乘以 0, 1, T 的情况
    let partial_t: Vec<u8> = stack1.iter().map(|&m| TNEG[m as usize]).collect();
    let partials = vec![
        vec![0; stack1.len()], //0乘任何数,都得0
        stack1.clone(),        //任何数乘1,等于它本身
        partial_t,             //任何数乘T(-1)等于相反数
    ];
    let mut result: Vec<u8> = vec![0];
    for (shift, &m2) in stack2.iter().rev().enumerate() {
        let mut part = partials[m2 as usize].clone();//用偏积表,m2当成下标,出可变副本
        part.resize(part.len() + shift, 0); // 更高效的偏移,低位补 0
        result = ternary_stack_adder(result, part);//加入当前部分积
    }
    result
}

/// 判断三进制数的符号(从高位到低位)
/// - 返回 0 表示全 0
/// - 返回 1 表示正数(首个非零位是 1)
/// - 返回 2 表示负数(首个非零位是 T)
pub fn ternary_sign(stack: &[u8]) -> u8 {
    let mut state: u8 = 0;
    for &digit in stack {
        state = TPOZ[state as usize][digit as usize];
    }
    state
}
 
/// 比较两个平衡三进制向量:返回 -1 (T), 0, 1
pub fn ternary_cmp(stack1: &Vec<u8>, stack2: &Vec<u8>) -> u8 {
    let diff=ternary_stack_sub(stack1.clone(), stack2.clone());
    let state=ternary_sign(&diff);
    state
}
 
 
fn main() {
    let stack1=vec![1,1,0,1];
    let stack2=vec![1,0,1,1];
    
    //println!("{:?}",ternary_stack_adder(stack1,stack2));
    //println!("{:?}",ternary_stack_sub(stack1,stack2));
    //print!("{:?}",ternary_mul_base(stack1,stack2));
    println!("{:?}",ternary_cmp(&stack1, &stack2));
    println!("{:?}",stack1);
}

        我的天,没有条件判断真的不行,但是上面的判断条件大复杂了,所以还是要简单一点,不然开销太大了,看看下面的数,找找大小规律:

十进制 平衡三进制 十进制 平衡三进制
0 0 0 0
1 1 -1 T
2 1T -2 T1
3 10 -3 T0
4 11 -4 TT
5 1TT -5 T11
6 1T0 -6 T10
7 1T1 -7 T1T
8 10T -8 T01
9 100 -9 T00
10 101 -10 T0T
11 11T -11 TT1
12 110 -12 TT0
13 111 -13 TTT

结合上面的表,平衡三进制从小到大:T/0/1,如果两个数列表格,即a与b比较大小,输出也用T/0/1,输出0表示两数相等,输出1表示a大于b,输出T表示a小于b,这样a在左侧,b在顶侧可列出逻辑表格:

TCMP T 0 1
T 0 T T
0 1 0 T
1 1 1 0

同样的,可得代码:

// **非零门(TPOZ)逻辑表 当为T1、0T、T0、TT时出T,当为1T、01、10、11时出1,双0出0 此门用于检测其最高位的正负性,出T为负数,出1为正数,出0则0 **
pub const TPOZ:[[u8; 3];3]= [
    [0, 1, 2],
    [1, 1, 1],
    [2, 2, 2],
];

// **比较门(TCMP)逻辑表 (a=b)输出 0、 (a > b)输出 +1、(a < b)输出 -1**
pub const TCMP:[[u8; 3];3]= [
    [0, 2, 1],
    [1, 0, 1],
    [2, 2, 0],
];

/// 判断三进制数的符号(从高位到低位)
/// - 返回 0 表示全 0
/// - 返回 1 表示正数(首个非零位是 1)
/// - 返回 2 表示负数(首个非零位是 T)
pub fn ternary_sign(stack: &[u8]) -> u8 {
    let mut state: u8 = 0;
    for &digit in stack {
        state = TPOZ[state as usize][digit as usize];
    }
    state
}

/// 比较两个平衡三进制大小(从高位到低位,位数要相同)
/// - 返回 0 表示相等
/// - 返回 1 表示 a > b
/// - 返回 2 表示 a < b
/// 向量:返回 -1 (T), 0, 1
pub fn ternary_cmp123(stack1: &[u8], stack2: &[u8]) -> u8 {
    let mut state: u8 = 0;
    for (&a, &b) in stack1.iter().zip(stack2.iter()) {
        state=TCMP[a as usize][b as usize];
        if state!=0{break;}//全部对比过,则相等
    }
    state
}
 
fn main() {
    let stack1=vec![1,0,1,1];
    let stack2=vec![1,1,0,1];
    
    println!("{:?}",ternary_cmp123(&stack1, &stack2));
    println!("{:?}",stack1);
}

完结!!!

多么精简的代码呀。。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐