public static int add( int number_1, int number_2 )
{
int sum = 0;
int carry = 0;
do
{
sum = number_1 ^ number_2;
carry = ( number_1 & number_2 ) << 1;
number_1 = sum;
number_2 = carry;
}
while ( carry != 0 );
return sum;
}
public static int minus(int a,int b)
{
return add(a,add(~b,1));
}
public static int multip(int a,int b)
{
int absoluteB,product=0;;
if(b<0)
{
absoluteB=add(~b,1);
product=addGetMultip(product,a,absoluteB);
product=add(~product,1);
}
else
{
absoluteB=b;
product=addGetMultip(product,a,absoluteB);
}
return product;
}
public static int division(int a,int b) throws ArithmeticException
{
if(b==0)
throw new RuntimeException("除数不能为零!");
int result=0;
int absoluteA,absoluteB;
if(a<0)
absoluteA=add(~a,1);
else absoluteA=a;
if(b<0)
absoluteB=add(~b,1);
else absoluteB=b;
int difference=absoluteA;
while(difference>=absoluteB)//如果b==0,必须抛出异常,否则将无限循环下去
{
difference-=absoluteB;
result++;
}
if((a>0&&b<0)||(a<0&&b>0))
result=add(~result,1);
return result;
}
private static int addGetMultip(int product,int base,int time)
{
int i=0;
while(i
以上位运算实现加法的代码我参考了网上的资源,然后减乘除则是依赖于加法自己实现的,可能有些不够精辟,但是能正常执行并得出结果。
接下来进入正题,对于加法运算的实现原理请参考:位运算实现加法的原理
通过测试,该加法计算方法对于负数也能够完美实现,但是在计算机语言中负数是以补码的形式存放的,也就是说一个正数的相反数就是该正数的二进制形式取反加一。
例如:对于字节型的1,在内存中的存放形式是0000 0001,而-1则是1的反码(1111 1110)加上1,即1111 1111。对于这样形式的负数仍能以上面的实现原理来理解吗,
也许你能,反正我是不能。于是我就思考为什么负数也能通过此方法进行运算。最后得到如下结论:
首先,既然我无法理解负数为什么能够用此方法进行计算,那么我就不把负数当做一个负数,而把整个数当做一个没有负数标记位的正数。
然后,我们可以取一个数,然后将其取反,不难知道,将这个数和其反码相加的结果永远是全部为1,例如0011 0101与1100 1010加起来就是1111 1111。如果这个数据类型有n位,那么用它表示的一个整数和它的反码的和的值可以用2^n-1的形式二进制形式来表示,即a+~a=2^-1。而我们知道相反数数的表示形式其实是反码加一,所以对于一个数a,其相反数-a的表示形式就是:-a=(2^n-1-a)+1=2^n-a 。
接着,当我们把负数当做正数来看的话,对于两个整数a和b,我们假设它们的最高位都为0,即我们所认识的正数,那么a+b=add(a,b)。那么当我们要计算a的相反数和b的和的时候,我们可以先得到a的相反数的表现形式2^n-a,但是我们把它看做一个正数,然后调用该方法add(2^n-a,b) ,计算的结果本来应当是是2^n-a+b的二进制形式。
1.当b>a的时候该结果的值已经大于2^n-1,结果是向第n+1位进一,但是计算机是不会保存这个一的,因为该数据类型只有n位,于是得到的二进制表现形式其实是2^n-a+b-2^n即b-a的二进制表现形式,显然这个数就是-a和b的和的值。