用Rust写平衡三进制乘法器
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);
}
完结!!!
多么精简的代码呀。。
更多推荐

所有评论(0)