补码一位乘法(Booth算法,C语言实现)
补码一位乘法
首先了解下什么是补码?
补码概念的理解,需要先从“模”的概念开始。 我们可以把模理解为一个容器的容量。当超出这个 容量时,会自动溢出。如:我们最常见到的时钟,其容量 是 12,过了 12 点之后,就会变为 1 点, 2 点……也就是 说,超过12的部分将被丢弃。那么,在这个例子当中,时钟 的模就是12。模的概念可以帮助我们理解补码的含义。
补码的引出:假设现在时钟的时针指向 4 点的位 置,要使其指向 3 点,可以怎么操作呢?很明显,共有 2 种方法,顺时针拨 11 格(+11),或逆时针拨 1 格(-1)。 (为了区分顺时针和逆时针,我们用正数表示顺时针方 向转动的距离,负数表示逆时针方向转动的距离) 从上面的例子,不难发现,+11 和-1 实现了同样的 作用。主要原因是时钟的模是 12,顺时针旋转代表加法 运算:4+11=15,而达到模的部分会自动溢出,即 15-12= 3,即到达 3 点的位置。逆时针旋转代表减法运算:4-1= 3。在这个例子当中,+11和-1 是完全等价的。也就是说, 负数-1 可以用正数+11 代替,这样就可以把减法运算改 为加法运算。也可以说:+11 就是-1 的补码(模为 12 的 情况下)。
具体的补码一位乘法(Booth算法)
Booth算法简介
Booth算法也就是补码1位乘的比较法。被乘数为[X]补,乘数为[Y]补,[P]补为乘积,按执行顺序得出每一步的部分积
[ P 0] 补 =0, [ P 1] 补 ={[ P 0] 补 +( Yn +1- Yn )[ X ] 补 } 2-1,
[ Pn +1] 补 ={[ Pn ] 补 +( Y 1- Y 0)[ X ] 补 }=[ X · Y ] 补 。 Booth算法的运算规则如下。
1)乘数的最低位为 Yn ,在其后再添加一位 Yn +1,其值为0。
2) Yi +1与 Yi 为相邻2位,( Yi +1- Yi )有“ 0”,“ 1”和“-1” 3种情况。
① Yi +1- Yi =0( Yi +1 Yi =00或11),部分积直接右移1位。
② Yi +1- Yi =1( Yi +1 Yi =10),部分积加[ X ] 补 ,右移1位。
③ Yi +1- Yi =-1( Yi +1 Yi =01),部分积加 [- X ] 补 ,右移1位。 3)按以上执行 n +1步,最后一步( i = n +1)不移动。
- 具体的算法可以看看这个链接https://www.cnblogs.com/xisheng/p/9260861.html
- 小啊鹏(木木大人)的C语言算法实现(修改版)
#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#include<stdlib.h> #define M 12 char * Input_X(char a[]);//输入函数X
char * Input_Y(char a[]);//输入函数Y
_Bool BoolInput(char a[]);//判断输入是否合法
char * GetTrue_form(char a[],char code[]);//由真值求原码
char * GetComplement(char a[],char b[]);//由原码求补码
char * GetComplementOperation(char a[]);//求补运算
char * Booth(char a[],char b[],char []);//补码一位乘法(Booth算法)
char for_mean(char a); int main()
{
char flag='Y';
while(1)
{
char X[M];//X的真值
char Y[M];//Y的真值
char X_Code[M];//X_原码
char Y_Code[M];//y_原码
char X_Complement_Code[M];//X_补码
char Y_Complement_Code[M];//Y_补码
char X_Y_Booth[M];//补码一位乘法的结果 char *X_Code_P;//X_原码的指针
char *Y_Code_P;//Y_原码的指针
char *X_Complement_Code_P;//X_补码指针
char *Y_Complement_Code_P;//X_补码指针 Input_X(X);
Input_Y(Y); X_Code_P=GetTrue_form(X,X_Code);
Y_Code_P=GetTrue_form(Y,Y_Code);
X_Complement_Code_P=GetComplement(X_Code,X_Complement_Code);
Y_Complement_Code_P=GetComplement(Y_Code,Y_Complement_Code); printf("X的原码是:%s\n",GetTrue_form(X,X_Code));
printf("Y的原码是:%s\n",GetTrue_form(Y,Y_Code));
printf("X的补码是:%s\n",X_Complement_Code);
printf("Y的补码是:%s\n",Y_Complement_Code);
printf("[XY]的真值是:%s\n",Booth(X_Complement_Code,Y_Complement_Code,X_Y_Booth));
for_mean(flag);
}
return 0;
}
//循环函数
char for_mean(char a)
{
char b[10];
while(1){
printf("是否需要继续运算:(Y/N)");
fflush(stdin);
setbuf(stdin, NULL);
scanf("%s",b);
if(strlen(b)!=1)
{
printf("输入错误!\n");
continue;
}
setbuf(stdin, NULL);
a=b[0];
if(a=='Y'||a=='y')
{
//printf("输入的是%c\n",a);
break;
}
if(a=='n'||a=='N')
{
//printf("输入的是%c\n",a);
printf("退出中,再见!\n");
exit(0);
}
}
return a;
}
//输入函数X
char * Input_X(char a[])
{
fflush(stdin);
printf("请输入你的二进制真值(被乘数)X=");
scanf("%s",a);
while(1)
{
if(BoolInput(a))
break;
scanf("%s",a);
}
printf("你输入的二进制真值X是:%s\n",a); return a;
}
//输入函数Y
char * Input_Y(char a[])
{
fflush(stdin);
printf("请输入你的二进制真值(乘数)Y=");
scanf("%s",a);
while(1)
{
if(BoolInput(a))
break;
scanf("%s",a);
}
printf("你输入的二进制真值Y是:%s\n",a);
return a;
} //判断输入是否合法
_Bool BoolInput(char a[])
{
int count = 0; //小数点出现的次数
//判断输入位数是否合法
if(strlen(a)>M-2 ||strlen(a)<3)
{
printf("对不起你输入的长度不对啊!请重新输入:");
a=NULL;
return false;
}
//判断输入的第一位是否正确!
if(a[0]!='0'&&a[0]!='-')
{
printf("你输入的第一位就错了啊! 请重新输入:");
a=NULL;
return false;
}
//判断输入为正数后的操作
if(a[0]=='0')
{
if(a[1]!='.')
{
printf("零后面应该是小数点啊,兄弟!! 请重新输入:");
return false;
}
}
//判断输入为负数后的操作
if(a[0]=='-')
{
if(a[1]!='0'||a[2]!='.')
{
printf("负号后面应该接的零啊,老哥!! 请重新输入:");
return false;
}
}
//判断是否有除0,1,-以外的字符输入
for(int i=1;i<strlen(a);i++)
{
if(a[i]!='0'&&a[i]!='1'&&a[i]!='.')
{
printf("老哥你输入的不是二进制的真值啊!请重新输入:");
a=NULL;
return false;
}
if(a[i]=='.')
{
count++;
}
}
//判断输入的小数点个数是否合法
if(count>1)
{
printf("老哥你输入的小数点有%d个,这多了啊!请重新输入",count);
a=NULL;
return false;
}
return true;
} //由真值求原码
char * GetTrue_form(char a[],char code[])
{
int flag=0;
//如果真值是负数符号为置为1
if(a[0]=='-')
{
code[0]='1';
if(a[1]=='0')
{
for(int i=1;i<strlen(a);i++)
{
if(a[i]=='1')
flag=1;
code[i]=a[i+1];
if(flag==0)
code[strlen(a)]='0';
}
code[strlen(a)+1]='\0';
return code;
}
//
else
{
for(int i=1;i<strlen(a);i++)
{
code[i]=a[i];
}
code[strlen(a)+1]='\0';
}
return code;
}
//反之置为0
else
{
for(int i=0;i<strlen(a);i++)
{
code[i]=a[i]; }
code[strlen(a)]='\0';
}
return code;
}
//原码转化补码
char * GetComplement(char a[],char b[])
{
for(int i=0;i<strlen(a);i++)
{
b[i]=a[i];
}
b[strlen(a)+1]='\0';
//正数的补码就是原码
if(b[0]=='0')
{
return b;
}
//负数的补码转化
if(b[0]=='1')
{
int j=0; //定位低位往高位遇到的第一个'1'.
for(int i=strlen(b);i>1;i--)
{
if(b[i]=='1')
{
j=i;
break;
}
}
//具体的原码转补码,低位往高位遇到的第一个'1'往前的取反,符号位不变!
for(int i=1;i<j;i++)
{
if(b[i]=='1')
{
b[i]='0';
continue;
}
if(b[i]=='0')
{
b[i]='1';
continue;
}
} }
return b;
} //求补运算,将一个数(包括正数和负数)所有二进制位(包括符号位和数值位)取反,然后在最低位加上1。
char * GetComplementOperation(char a[])
{
//取反
for(int i=0;i<strlen(a);i++)
{
if(a[i]=='1')
{
a[i]='0';
continue;
}
else if(a[i]=='0')
{
a[i]='1';
}
}
//加1操作
//判断最后一位是不是0如果是0则只在最后一位加1
if(a[strlen(a)-1]=='0')
{
a[strlen(a)-1]='1';
return a;
}
for(int i=strlen(a);i>0;i--)
{
if(a[i]=='1')
{
a[i]=='0';
continue;
}
if(a[i]=='0')
{
a[i]=='1';
break;
}
}
return a;
} //补码一位乘法(Booth算法)
char * Booth(char a[],char b[],char d[])
{
char c='0';//进位
char b_Temp;//一位过程中需要的临时变量
char X_ComplementOperation[M];//[-X]补
char a_Temp[M];
//首先统一位数
int X_i;//x补码的长度
int Y_i;//y补码的长度
int Length_Difference=0;//长度的差值
X_i=strlen(a);
Y_i=strlen(b);
printf("x的位数%d和y的位数是:%d\n",X_i,Y_i);
printf("X的补码为:%s\n",a);
printf("Y的补码为:%s\n",b);
if(X_i>Y_i)
{
printf("我比Y的位数大\n");
Length_Difference=X_i-Y_i;
for(int i=0;i<Length_Difference;i++)
{
b[Y_i+i]='0';
}
b[Y_i+Length_Difference]='\0';
}
if(X_i<Y_i)
{
printf("我比Y的位数小\n");
Length_Difference=Y_i-X_i;
for(int i=0;i<Length_Difference;i++)
{
a[X_i+i]='0';
}
a[Y_i+Length_Difference+1]='\0';
}
printf("\n");
printf("统一符号位X的补码变为:%s\n",a);
printf("统一符号位Y的补码变为:%s\n",b);
printf("\n");
//把X的补码变为双符号位的
int X_Length=0;//X的长度
int Y_Length=0;//Y的长度
X_Length=strlen(a);
Y_Length=strlen(b); char temp;
temp=a[0];
for(int i=strlen(a)-1;i>0;i--)
{
a[i+1]=a[i];
if(a[i]=='.')
break;
}
a[0]=temp;
a[1]=temp;
a[X_Length+1]='\0'; printf("将X的补码变为双符号位:%s\n",a);
stpcpy(a_Temp,a);
//求[-X]补
GetComplementOperation(a_Temp);
for(int i=0;i<strlen(a_Temp);i++)
{
X_ComplementOperation[i]=a_Temp[i];
}
X_ComplementOperation[strlen(a_Temp)]='\0';
printf("X求补是:%s\n",X_ComplementOperation); //对Y的最后一位补0操作 b[Y_Length]='0';
b[Y_Length+1]='\0'; printf("对Y的补码最低位加0后:%s\n",b); //具体的运算过程
X_Length=strlen(a);
Y_Length=strlen(b);
char Cn;//高位
char Cn_1;//地位
char Register[X_Length+Y_Length];//寄存器数组 //初始化寄存器数组
for(int i=0;i<X_Length;i++)
{
if(a[i]=='.')
{
Register[i]='.';
continue;
}
Register[i]='0';
}
for(int i=0;i<Y_Length;i++)
{
Register[i+X_Length]=b[i];
}
Register[X_Length+Y_Length]='\0'; printf("寄存器初始的数据:%s",Register); //除去小数点Register
for(int i=0;i<strlen(Register);i++)
{
if(Register[i]=='.')
{
for(int j=i;j<strlen(Register);j++)
{
Register[j]=Register[j+1];
}
}
}
printf("寄存器初始的数据:%s\n",Register);
//除去小数点X_ComplementOperation
for(int i=0;i<strlen(X_ComplementOperation);i++)
{
if(X_ComplementOperation[i]=='.')
{
for(int j=i;j<strlen(X_ComplementOperation);j++)
{
X_ComplementOperation[j]=X_ComplementOperation[j+1];
}
}
}
//除去小数点a
for(int i=0;i<strlen(a);i++)
{
if(a[i]=='.')
{
for(int j=i;j<strlen(a);j++)
{
a[j]=a[j+1];
}
}
}
//开始进行比较
char flag='D';
for(int i=0;i<Y_Length-2;i++)
{
Cn=Register[strlen(Register)-2];
Cn_1=Register[strlen(Register)-1];
if(Cn=='0'&&Cn_1=='0')
flag='A';
if(Cn=='1'&&Cn_1=='1')
flag='A';
if(Cn=='0'&&Cn_1=='1')
flag='B';
if(Cn=='1'&&Cn_1=='0')
flag='C';
printf("操作数的高位是:%c低位是:%c\n",Cn,Cn_1);
switch (flag)
{
//操作1:右移一位
case 'A':
{
if(i<Y_Length-3)
{
for(int j=strlen(Register)-1;j>1;j--)
{
Register[j]=Register[j-1];
}
Register[1]=Register[0];
}
printf("移位操作后寄存器的数据:%s\n",Register);
break;
} //操作2:加上X的补,并右移一位
case 'B':
{
//加的操作
//printf("a的值是:%s\n",a); for(int j=strlen(a)-1;j>=0;j--)
{
//设置尾是否有进位数
if(j==strlen(a)-1)
{
if(Register[j]=='1'&& a[j]=='1')
{
c='1';
Register[j]='0';
continue;
}
if(Register[j]=='1'&& a[j]=='0')
{
c='0';
Register[j]='1';
continue;
}
if(Register[j]=='0'&& a[j]=='1')
{
c='0';
Register[j]='1';
continue;
}
}
if(Register[j]=='1')
{
if(a[j]=='0' && c=='0')
{
continue;
}
else if(a[j]=='0' &&c=='1')
{
Register[j]='0';
c='1';
continue;
}
else if(a[j]=='1'&& c=='0')
{
Register[j]='0';
c='1';
continue;
}
else if(a[j]=='1'&& c=='1')
{
Register[j]='1';
c='1';
continue;
}
}
if(Register[j]=='0')
{
if(a[j]=='0' && c=='0')
{
continue;
}
else if(a[j]=='0' &&c=='1')
{
Register[j]='1';
c='0';
continue;
}
else if(a[j]=='1'&& c=='0')
{
Register[j]='1';
c='0';
continue;
}
else if(a[j]=='1'&& c=='1')
{
Register[j]='0';
c='1';
continue;
}
}
} //printf("未移位寄存器的数据:%s\n",Register);
//移位的操作
if(i<Y_Length-3)
{
for(int j=strlen(Register)-1;j>1;j--)
{
Register[j]=Register[j-1];
}
Register[1]=Register[0];
}
printf("B操作后寄存器的数据:%s\n",Register);
break;
} //操作3:加上-X的补,并右移一位
case 'C':
{
//加-x补码的操作
//printf("X_ComplementOperation的值是:%s",X_ComplementOperation);
for(int j=strlen(X_ComplementOperation)-1;j>=0;j--)
{
//设置尾是否有进位数
if(j==strlen(a)-1)
{
if(Register[j]=='1'&& a[j]=='1')
{
c='1';
Register[j]='0';
continue;
}
if(Register[j]=='1'&& a[j]=='0')
{
c='0';
Register[j]='1';
continue;
}
if(Register[j]=='0'&& a[j]=='1')
{
c='0';
Register[j]='1';
continue;
}
} //加
if(Register[j]=='1')
{
if(X_ComplementOperation[j]=='0' && c=='0')
{
continue;
}
else if(X_ComplementOperation[j]=='0' &&c=='1')
{
Register[j]='0';
c='1';
continue;
}
else if(X_ComplementOperation[j]=='1'&& c=='0')
{
Register[j]='0';
c='1';
continue;
}
else if(X_ComplementOperation[j]=='1'&& c=='1')
{
Register[j]='1';
c='1';
continue;
}
}
if(Register[j]=='0')
{
if(X_ComplementOperation[j]=='0' && c=='0')
{
continue;
}
else if(X_ComplementOperation[j]=='0' &&c=='1')
{
Register[j]='1';
c='0';
continue;
}
else if(X_ComplementOperation[j]=='1'&& c=='0')
{
Register[j]='1';
c='0';
continue;
}
else if(a[j]=='1'&& c=='1')
{
Register[j]='0';
c='1';
continue;
}
}
} //printf("未移位是寄存器的数据:%s\n",Register);
//移位的操作
if(i<Y_Length-3)
{
for(int j=strlen(Register)-1;j>1;j--)
{
Register[j]=Register[j-1];
}
Register[1]=Register[0];
}
printf("C操作后寄存器的数据:%s\n",Register);
break;
}
default:
{
printf("对不起,出现无法解决的错误,程序将要退出!\n");
exit(0);
}
}
}
printf("最后寄存器的数据:%s\n",Register);
//转化为补码
for(int i=0;i<strlen(Register)-2;i++)
{
d[i]=Register[i];
}
d[strlen(Register)-2]='\0';
if(d[0]=='0')
{
d[1]='.';
}
if(d[0]=='1')
{
d[1]='.';
d[strlen(Register)]='\0';
}
printf("[X*Y]补是:%s\n",d);
//转化为真值
if(d[0]=='1')
{
d[0]='-';
d[1]='0';
for(int i=strlen(d);i>2;i--)
{
d[i]=d[i-1];
}
d[2]='.';
d[strlen(Register)]='\0';
}
return d;
}
我也知道大家可能主要是需要算法的具体实现,因此代码中注解较多。
这里我也欢迎大家交流,希望大家可以指出代码里的错误和不足,谢谢!
参考文献
[1]武涛,智洋,白丽珍.三种机器码的联系与剖析[J].大学教育,2017(04):18-19+22.
[2]王晓东,富坤,耿恒山,秘海晓,孙晓丽.在8位微程序控制的模型计算机中Booth算法的实现[J].河北科技大学学报,2012,33(05):443-447.
下面说下我的运行环境(在window VS中可能无法运行):
操作系统:Ubuntu16
编译器:gcc
补码一位乘法(Booth算法,C语言实现)的更多相关文章
- 补码一位乘法 Booth算法 Java简易实现
本文链接:https://www.cnblogs.com/xiaohu12138/p/11955619.html. 转载,请说明出处. 本程序为简易实现补码一位乘法,若代码中存在错误,可指出,本人会不 ...
- Booth算法: 补码一位乘法公式推导与解析
以下讲解内容出自<计算机组成原理(第三版)>(清华大学出版社) 大二学生一只,我的计组老师比较划水,不讲公式推导,所以最近自己研究了下Booth算法的公式推导,希望能让同样在研究Booth ...
- 「C语言」原码反码补码与位运算
尽管能查到各种文献,亲自归纳出自己的体系还是更能加深对该知识的理解. 本篇文章便是在结合百度百科有关原码.反码.补码和位运算的介绍并深度借鉴了张子秋和Liquor相关文章后整理而出. 目录 ...
- BOOTH 算法的简单理解
学习FPGA时,对于乘法的运算,尤其是对于有符号的乘法运算,也许最熟悉不过的就是 BOOTH算法了. 这里讲解一下BOOTH算法的计算过程,方便大家对BOOTH的理解. 上图是BOOTH ...
- Booth算法
Booth算法 算法描述(载自维基百科) 对于N位乘数Y,布斯算法检查其2的补码形式的最后一位和一个隐含的低位,命名为y-1,初始值为0.对于yi, i = 0, 1, ..., N - 1,考察yi ...
- 【转】位置式、增量式PID算法C语言实现
位置式.增量式PID算法C语言实现 芯片:STM32F107VC 编译器:KEIL4 作者:SY 日期:2017-9-21 15:29:19 概述 PID 算法是一种工控领域常见的控制算法,用于闭环反 ...
- PID算法(C语言)
/************ PID算法(C语言) ************/ #include <stdio.h> #include<math.h> struct _pid { ...
- 为 32 位单片机设计的脚本语言 Berry
Berry是一款一款为32位单片机设计的脚本语言.Berry解释器使用C89标准实现,该语言可以在RAM或ROM很小的设备上运行. 尽管Berry的体积很小,但是它也支持class以及闭包等功能,使得 ...
- PageRank算法R语言实现
PageRank算法R语言实现 Google搜索,早已成为我每天必用的工具,无数次惊叹它搜索结果的准确性.同时,我也在做Google的SEO,推广自己的博客.经过几个月尝试,我的博客PR到2了,外链也 ...
随机推荐
- MySQL简版(二)
第一章 表的约束 1.1 概念 对表中的数据进行限定,保证数据的正确性.有效性和完整性. 1.2 分类 主键约束:primary key. 非空约束:not null. 唯一约束:unique. 外键 ...
- Python中的网络扫描大杀器Scapy初探
Python中的网络扫描大杀器Scapy初探 最近经历了Twisted的打击,这个网络编程实在看不懂,都摸不透它的内在逻辑,看来网络编程不是那么好弄的.还好,看到了scapy,这种网络的大杀器 ...
- 043:Django使用原生SQL语句操作数据库
Django使用原生SQL语句操作数据库 Django配置连接数据库: 在操作数据库之前,首先先要连接数据库.这里我们以配置 MySQL 为例来讲解. Django 连接数据库,不需要单独的创建一个连 ...
- [洛谷P4823] TJOI2013 拯救小矮人
问题描述 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口. 对于每一个小矮人,我们知道他从 ...
- 【leetcode】523. Continuous Subarray Sum
题目如下: 解题思路:本题需要用到这么一个数学定理.对于任意三个整数a,b,k(k !=0),如果 a%k = b%k,那么(a-b)%k = 0.利用这个定理,我们可以对数组从头开始进行求和,同时利 ...
- delphi 10.3 控件遮挡 webbrowser
听闻10.3的新特性之一,webbrowser可以被其他控件遮挡, 在等待10.3.1出来后才开始来尝鲜, 但在webbrowser上添加控件后, 发现控件还是被挡住了, 研究发现需要将控件的cont ...
- 容器镜像服务 联手 IDE 插件,实现一键部署、持续集成与交付
容器技术提供了一种标准化的交付方式,将应用的代码以及代码环境依赖都打包在一起,成为一个与环境无关的交付物,可以被用在软件生命周期的任何阶段,彻底改变了传统的软件交付方式. 甚至可以说,是在容器技术之后 ...
- CF543B Destroying Roads 枚举 + 思维 + BFS
Code: #include <bits/stdc++.h> #define ll long long #define setIO(s) freopen(s".in", ...
- BZOJ 2097: [Usaco2010 Dec]Exercise 奶牛健美操 二分 + 贪心 + 树上问题
Code: #include<bits/stdc++.h> using namespace std; #define setIO(s) freopen(s".in",& ...
- 倍增O(1)求区间&值与|值
;i<=n;++i) f[i][]=a[i],g[i][]=a[i]; ;(<<j)<=n;++j) ;(i+(<<j)-)<=n;i++) { f[i][j ...