今天看到《编码:隐匿在计算机软硬件背后的语言》的第十二章:二进制加法器。讲述了全加器,半加器的原理以及如何实现加法。实现加法时所使用的全加器,半加器中包含的所有逻辑门在C语言中都有相应的运算符,就想着能不能利用C语言中的运算符实现不用加号的加法运算。
首先,半加器的样子: 全加器的样子:
二进制加法器的样子:
以下为完全按照二进制加法器的计算流程写成的C语言代码
#include"stdio.h" int add(int a,int b) { ,aa,bb,t=; unsigned i;//由于需要计算31位,但是int的第32位是符号位,故定义成无符号型 ;i<=) { aa=i&a;//a的本位 bb=i&b;//b的本位 sum|=aa^bb^t;//aa 和 bb 和 前位的进位 求和 t&=aa^bb;//aa 和 bb 的加和位 与 前位的进位 求进位位 t|=aa&bb;//aa 和 bb 的进位位 与 上式的进位位 求或 (如果有进位,上下两个式子只有一个需要进位) t<<=; } return sum; } int main() { int a,b; while(~scanf("%d%d",&a,&b)) printf("%d %d\n",add(a,b),a+b); ; }
记得以前在网上见到过不使用加号实现加法的方法,于是又从网上找了找。一共找到了三个方法,其中第一种思想与二进制加法器的思想基本相同,但因为不是一位一位运算的,所以有一个地方略有不同,以下为代码
#include"stdio.h" int add(int a,int b) { ) return a; int sum=a^b;//sum和a存储的是加和位 ;//carry和b存储的是进位位 //这里比最开始的代码少了一个求或的运算 //因为这个代码是所有位一起运算的,所以当某一位运算有进位到下一位时 //下一位的两个操作数不会存在都是1的情况 //因为一开始都是1的话,在本次计算之前就已经进位到下一位了 //而最开始的一位一位的计算方法,存在这种情况,所以需要单独处理 return add(sum,carry); } int main() { int a,b; while(~scanf("%d%d",&a,&b)) printf("%d %d\n",add(a,b),a+b); ; }
第二种第三种方法属于利用计算机内存及函数的运算机制来计算的方法,以下为第二种方法代码
#include"stdio.h" int main() { int a,b; while(~scanf("%d%d",&a,&b)) printf("%d\n",printf("%*s%*s",a,"",b,"")); ; //这种方法利用的是printf函数的返回值及*操作符的原理来计算两个数相加的 //1.因为printf函数是字符流的格式化输出函数 // 所以printf函数的返回值是:输出字符串中所含字符个数(int型) //2.printf函数中的*操作符用来指定输出字符串的宽度 // 这个值由后面对应字符串参数前的一个整数参数指定 //这样在上例中printf输出的字符串是最大宽度为a+b的两个空字符,不足的地方用空格补全 //最终函数的返回值是a+b //但是这个方法有一个问题:printf函数中的printf函数输出的空格会输出在加和结果之前 //因此这个方法并不能按照正常格式输出a+b }
以下为第三种方法的代码
#include"stdio.h" int add(int a,int b) { return (int)(&((char*)a)[b]); //这个求加和的思路是利用数组在内存中存储的连续性 //a[b]与*(a+b)是等价的 //所以要求a+b的值只需求出a[0]到a[b]占内存的宽度除去单个数据所占宽度即可 //具体计算公式:a+b=(int)(&a[b]-&a[0])/sizeof(a[0]) } int main() { int a,b; while(~scanf("%d%d",&a,&b)) printf("%d %d\n",add(a,b),a+b); ; }
a+b=a-(-b)这种抖机灵的方法就不提了...
以下为参考
第一种方法:求两个数的和(不用+-*/)
第二种方法:C语言中不使用操作符实现两个数相加
第三种方法:C语言中如何不使用加号,完成两个数字相加