补码的乘法-布斯乘法

2024-03-28 04:59
文章标签 乘法 补码 布斯

本文主要是介绍补码的乘法-布斯乘法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

本篇文章讲解如何通过逻辑门的形式来实现补码的乘法操作

布斯乘法

A.D.Booth提出了一种补码相乘算法,可以将符号位与数值位合在一起参与运算,直接得出用补码表示的乘积,且正数和负数同等对待。这种算法被称之为Booth (布斯)乘法
下面有两个变量值 X X X Y Y Y
Y Y Y用二进制表示为
Y = y n − 1 y n − 2 … y 2 y 1 y 0 Y = y_{n-1}y_{n-2}\ldots y_2y_1y_0 Y=yn1yn2y2y1y0
因为Y是用补码表示的,所以Y的值可以通过下面的公式计算:
Y = − y n − 1 2 n − 1 + y n − 2 2 n − 2 + … + y 1 2 1 + y 0 2 0 = − y n − 1 2 n − 1 + ∑ i = 0 n − 2 y i 2 i = − y n − 1 2 n − 1 + y n − 2 2 n − 1 − y n − 2 2 n − 2 + … + y 1 2 2 − y 1 2 1 + y 0 2 1 − y 0 = ( y n − 2 − y n − 1 ) 2 n − 1 + ( y n − 3 − y n − 2 ) 2 n − 2 + … + ( y 0 − y 1 ) 2 1 + ( 0 − y 0 ) = ∑ i = 0 n − 1 ( y i − 1 − y i ) 2 i \begin{aligned} Y &= -y_{n-1}2^{n-1} + y_{n-2}2^{n-2} + \ldots+y_12^1+ y_02^0\\ &=-y_{n-1}2^{n-1} + \sum_{i=0}^{n-2}y_i2^i \\ &=-y_{n-1}2^{n-1} + y_{n-2}2^{n-1}-y_{n-2}2^{n-2}+\ldots+y_12^{2}-y_{1}2^{1}+y_02^{1}-y_0\\ &=(y_{n-2}-y_{n-1})2^{n-1}+(y_{n-3}-y_{n-2})2^{n-2}+\ldots+(y_0-y_1)2^1+(0-y_0)\\ &=\sum_{i=0}^{n-1}(y_{i-1}-y_{i})2^{i} \end{aligned} Y=yn12n1+yn22n2++y121+y020=yn12n1+i=0n2yi2i=yn12n1+yn22n1yn22n2++y122y121+y021y0=(yn2yn1)2n1+(yn3yn2)2n2++(y0y1)21+(0y0)=i=0n1(yi1yi)2i
因为 X X X Y Y Y都是n位数据,所以 X × Y X\times Y X×Y可能占用2n位。
我们先假设 Y Y Y乘以 2 − n 2^{-n} 2n
X × Y × 2 − n = X × ∑ i = 0 n − 1 ( y i − 1 − y i ) 2 i × 2 − n = X × ∑ i = 0 n − 1 ( y i − 1 − y i ) 2 − ( n − i ) = P n \begin{aligned} X\times Y\times2^{-n} &= X\times \sum_{i=0}^{n-1}(y_{i-1}-y_{i})2^{i}\times2^{-n}\\ &=X\times \sum_{i=0}^{n-1}(y_{i-1}-y_{i})2^{-(n-i)}\\ &=P_{n} \end{aligned} X×Y×2n=X×i=0n1(yi1yi)2i×2n=X×i=0n1(yi1yi)2(ni)=Pn
即然我们假设这个值等于 P n P_{n} Pn了,那么我们可以推测 P n − 1 P_{n-1} Pn1的值
P n − 1 = X × ∑ i = 0 n − 2 ( y i − 1 − y i ) 2 − ( n − 1 − i ) P_{n-1} = X\times \sum_{i=0}^{n-2}(y_{i-1}-y_{i})2^{-(n-1-i)} Pn1=X×i=0n2(yi1yi)2(n1i)
然后我们能得出两个挨着的一般性公式 P i P_{i} Pi P i − 1 P_{i-1} Pi1的关系
P i = 2 − 1 ( P i − 1 + ( y i − 2 − y i − 1 ) X ) , i = 1 , 2 … , n − 1 P_{i} = 2^{-1}(P_{i-1} + (y_{i-2}-y_{i-1})X),i = 1,2\ldots,n-1 Pi=21(Pi1+(yi2yi1)X)i=1,2,n1

根据上面的公式,我们发现,可以先计算 P 0 P_{0} P0,然后通过 P 0 P_{0} P0计算 P 1 P_{1} P1,然后通过 P 1 P_{1} P1计算 P 2 P_{2} P2,然后就可以依次往后计算出 P n P_{n} Pn,如果计算 X × Y X\times Y X×Y,我们可以按照下面的步骤进行:

  1. 假设 P 0 = 0 P_{0}=0 P0=0,假设 y − 1 = 0 y_{-1}=0 y1=0
  2. 从y的最右侧位开始,先比较 y 0 y_0 y0 y − 1 y_{-1} y1
  3. 如果 y 0 y − 1 = = 00 y_0y_{-1}==00 y0y1==00 P 0 P_0 P0右移一位
  4. 如果 y 0 y − 1 = = 01 y_0y_{-1}==01 y0y1==01 P 0 + X P_0+X P0+X然后,右移一位
  5. 如果 y 0 y − 1 = = 10 y_0y_{-1}==10 y0y1==10 P 0 − X P_0-X P0X然后,右移一位
  6. 如果 y 0 y − 1 = = 11 y_0y_{-1}==11 y0y1==11 P 0 P_0 P0右移一位
  7. 右移后得到 P 1 P_{1} P1,比较位向左移动一位,如果没有超过最大位,跳转到2
  8. 如果超过最高位了, P n P_n Pn就是结果

注意:在此之前,其实 P n = X × Y × 2 − n P_n =X\times Y\times2^{-n} Pn=X×Y×2n,并且我们发现在上述步骤中结果一直在向右移,所以,我们可以把初始结果放在高n位上,这样向右移动不会丢失数据,并且也相当于乘了 2 n 2^{n} 2n,结果刚好是想要的值。

通过上面的步骤可以看出,乘法被分解成一系列加减和移位操作的顺序集合,我们之前已经实现了串行进位加法器和并行进位加法器,并且实现了一个桶形移位器

下面看一个实际的例子:
假设X = 100,Y = 120;
用二进制表示为X = 01100100,Y= 01111000,即然8位能够放下数据,为了书写方便,我们假设XY都为8位,结果为16位数据,假设结果为R = 0;

  1. 比较 y 0 y_0 y0 y − 1 y_{-1} y1, y 0 y − 1 = 00 y_0y_{-1}=00 y0y1=00,R=00000000 00000000,右移后值不变
  2. 比较 y 1 y_1 y1 y 0 y_0 y0, y 1 y 0 = 00 y_1y_0=00 y1y0=00,R=00000000 00000000,右移后值不变
  3. 比较 y 2 y_2 y2 y 1 y_1 y1, y 2 y 1 = 00 y_2y_1=00 y2y1=00,R=00000000 00000000,右移后值不变
  4. 比较 y 3 y_3 y3 y 2 y_2 y2, y 3 y 2 = 10 y_3y_2=10 y3y2=10,R=00000000 00000000,R-X后右移
    R-X = R(高位) + (~X) + 1= 10011100 00000000,右移后为11001110 00000000
    注意:是在R的高位上操作,并且右移为算数右移,补符号位
  5. 比较 y 4 y_4 y4 y 3 y_3 y3, y 4 y 3 = 11 y_4y_3=11 y4y3=11,R=11001110 00000000,右移后为11100111 00000000
  6. 比较 y 5 y_5 y5 y 4 y_4 y4, y 5 y 4 = 11 y_5y_4=11 y5y4=11,R=11100111 00000000,右移后为11110011 10000000
  7. 比较 y 6 y_6 y6 y 5 y_5 y5, y 6 y 5 = 11 y_6y_5=11 y6y5=11,R=11110011 10000000,右移后为11111001 11000000
  8. 比较 y 7 y_7 y7 y 6 y_6 y6, y 7 y 6 = 01 y_7y_6=01 y7y6=01,R=11111001 11000000,R+X后右移,R+X = 01011101 11000000, 右移后为00101110 11100000

计算完成,00101110 11100000 = 12000,与结果相符

布斯乘法在电路的实现

我们在前面讲述算法执行过程的时候,把结果数据放在了高n位,这样有两个好处:

  • 正好抵消了之前公式中乘的 2 − n 2^{-n} 2n
  • 在算法执行过程中结果数据总要右移,把结果数据放在高位,右移的时候不会丢失数据

并且每一步我们都会从右往左比较Y的位值,相当于我们每步都右移Y,然后比较Y的最低两位,但是第一步的时候我们还有一个 y − 1 = 0 y_{-1}=0 y1=0,所以我们可以这么设计:

  • 假设Y有n位,我们设计的电路有n+1根线,Y的值放在 n ~ 1 n~1 n1位, y − 1 y_{-1} y1的值放在0位
  • 这样,每一步的比较操作我们只需要右移电路一位,然后比较最低的两位值即可

即然结果数据和Y的值都右移,并且每步骤都右移1位,那么我们可以设计一个通用的电路:

  • 假设Y有n位,我们设计的电路有2n+1位,数据结果保存到 2 n ~ n + 1 2n~n+1 2nn+1位,Y的值放在 n ~ 1 n~1 n1位, y − 1 y_{-1} y1的值放在0位
  • 最终的结果就是高2n位的数据

下面给出电路图:
在这里插入图片描述

图中表示的是32位的布斯乘法电路图,电路的执行步骤如下:

  • 我们假设乘积寄存器P+乘数寄存器Y+最右边保存 y − 1 y_{-1} y1的值统称为R。
  • 默认乘积寄存器P的值为0,最右边保存 y − 1 y_{-1} y1的值为0,乘数寄存器Y的值和被乘数寄存器X的值被输入,计数器为0,时钟用来增加计数器的值
  • 每一步时钟,检查R的第两位,根据值的不同执行不同的电路逻辑
    • 00或者11,R右移,执行下一步
    • 01,执行加法操作,结果保存到乘积寄存器P,R右移,执行下一步
    • 10,执行减法操作,结果保存到乘积寄存器P,R右移,执行下一步
  • 计数器等于32,输出结果乘积寄存器P+乘数寄存器Y,结束

算术一位右移

虽然我们实现了桶形移位器,但是在当前的乘法运算中,有点大材小用,如果我们仅仅实现一个一位的右移操作,电路将变得很简单,我们直接给出C语言描述git地址

/*** 单位右移操作,为了实现布斯乘法专门定义的右移电路,支持129位* in_1:128~65位,用于存放乘积寄存器P* in_2:64~1位,用于存放乘数寄存器Y* in_1:0位,用于存放临时比较的值* isLogic:是否是逻辑右移*/
extern void alu_shift_right_1(long* in_1,long*  in_2,long*  in_3,long isLogic);void alu_shift_right_1(long* in_1,long* in_2,long*  in_3,long isLogic)
{// 先赋值最低位*in_3 = (*in_2)&1;// in_1的最低位给in_2的最高位unsigned long a = *in_2;*in_2 = (a>>1)| ((*in_1)&1)<<(sizeof(long)*8-1);// in_1右移1位if(isLogic){unsigned long b = *in_1;*in_1 = b>>1;}else{*in_1 = (*in_1)>>1;}
}

布斯乘法的C语言描述

最后给出布斯乘法的C语言描述,我们把结果存在两个long类型的数值中,out_1保存高位,out_2保存低位。git地址

/*** 使用布斯乘法算法计算两个数相乘* in_1:输入1* in_2:输入2* out_1:输出高位* out_2:输出低位*/
extern void alu_booth_times(long in_1, long in_2,long* out_1, long* out_2);void alu_booth_times(long in_1, long in_2,long* out_1, long* out_2)
{// y-1位,默认为0long lastBit = 0;// 保存结果的高位*out_1 = 0;long c = 0;// 计数器for(int i = 0; i<sizeof(long)*8;i++){long temp = in_2&1;if(temp == lastBit)// 直接右移{alu_shift_right_1(out_1,&in_2,&lastBit,0);}else if(lastBit==1)// 01,相加,然后右移{c = 0;*out_1 = alu_add_bcla_64(*out_1,in_1,sizeof(long)*8,&c);alu_shift_right_1(out_1,&in_2,&lastBit,0);}else// 10,相减,然后右移{*out_1 = alu_sub_bcla_64(*out_1,in_1,sizeof(long)*8);alu_shift_right_1(out_1,&in_2,&lastBit,0);}}*out_2 = in_2;
}

这篇关于补码的乘法-布斯乘法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/854512

相关文章

hdu 6198 dfs枚举找规律+矩阵乘法

number number number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description We define a sequence  F : ⋅   F0=0,F1=1 ; ⋅   Fn=Fn

高精度加法,乘法,阶乘

#include <iostream>#include <map>#include <string>#include <algorithm>using namespace std;const int Max = 50000;string str1,str2;/***********乘法***********/void chenfa(){cin >> str1>>str2;int a

乘法问题c++

题目描述 小 A 最近刚刚学习了乘法,为了帮助他练习,我们给他若干个正整数,并要求他将这些数乘起来。 对于大部分题目,小 A 可以精准地算出答案,不过,如果这些数的乘积超过 ,小 A 就不会做了。 请你写一个程序,告诉我们小 A 会如何作答。 输入 第一行一个整数 n,表示正整数的个数。 接下来 n行,每行一个整数a 。小 A 需要将所有的 a乘起来。 保证n<=50,a<=100. 输出

原码、反码、补码新解

世界上有10中人,一种懂二进制,一种不懂二进制。我们习惯了十进制计数,乍看到二进制,有点别扭,认识后慢慢发现它的神奇:有点一生二,二生万物的意思。十进制和二进制的部分对应关系如下: 小范围的十进制运算,我们操练起来麻麻溜溜的,二进制的运算相信你也不差,然,碰到十进制转二进制的运算就有点蒙圈了。 计算机 CPU 的运算器只实现了加法器,没有实现减法器。但,我们可以通过加上一个负数来实现减法运

机器学习经典算法之-----最小二乘法

一.背景    5月9号到北大去听hulu的讲座《推荐系统和计算广告在视频行业应用》,想到能见到传说中的项亮大神,特地拿了本《推荐系统实践》求签名。讲座开始,主讲人先问了下哪些同学有机器学习的背景,我恬不知耻的毅然举手,真是惭愧。后来主讲人在讲座中提到了最小二乘法,说这个是机器学习最基础的算法。神马,最基础,我咋不知道呢! 看来以后还是要对自己有清晰认识。    回来赶紧上百度,搜了下什么是最

【高精度】-DLUTOJ-1176-大数乘法

题目链接:http://acm.dlut.edu.cn/problem.php?id=1176 题目描述:赤裸的大数乘法 解题思路: 突然想到自己没写过高精度乘法,就回咱们自己OJ上找出了这道题,赤裸的高精度乘法而已,没想到依然觉得不好写,准确说来是我从小到大算乘法的习惯使我产生了错觉:“ 想写大数乘法就得先写一个大数加法出来 ”。喂!我短路了半天才想明白,int 数组里可以存个两位数啊,再

C语言操作符详解1(含进制转换,原反补码)

文章目录 一、操作符的分类二、二进制和进制转换1.二进制与十进制的相互转换2,二进制与八进制的相互转换3.二进制与十六进制的相互转换 三、原码、反码和补码四、移位操作符1.左移操作符(1)左移操作符移位方法(2)左移操作符规律总结 2.右移操作符(1)逻辑右移移位方法(2)逻辑右移规律总结(3)算术右移移位方法(4)算术移位规律总结 五、位操作符:&、|、^、~1.按位与操作符&2.按位或

大整数问题,乘法,加法,阶乘

//大整数相乘 //c[i+j] += a[i]*b[j];数组的每一位相乘然后相加,并得到最终结果 //再考虑进位问题  #include <string.h> #include <stdio.h> #define SIZE 50 int a[SIZE],b[SIZE],c[SIZE*2]; void big_multi(int a[],int b[],int c[]

HDU 1005(矩阵乘法)

A number sequence is defined as follows: f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7. Given A, B, and n, you are to calculate the value of f(n). 题意:给出一个递推公式,求第N项。 题解:开始试图找出一个能够直接算的递