通过位运算实现两个整数加、减、乘、除以及两个变量的交换

本文详细介绍了使用位运算实现整数加、减、乘、除及两个变量交换的方法,并通过代码实现验证了算法的有效性。

有的时候,出于精度与大小或是效率等方面的考虑,我们需要通过位运算实现两个数加、减、乘、除、两个变量交换。这里将详细的总结一下用位运算来实现整数的四则运算以及两个变量的交换。位运算的操作符有|、&、^、~、>>、<<,如果对这些操作符还不很了解,可以查看这里

加法运算

因为位运算符是按位来运算的,那么我们先看二进制的1位数相加
1 + 1 = 10
1 + 0 = 1
0 + 1 = 1
0 + 0 = 0
那么,此时我们需要在脑海里联想使用什么办法能实现这样的效果呢?于是我们发现了一个规律,两个1位二进制整数进行异或运算,结果等于其右边第一位数上的数字(设为A)。两个1位二进制整数进行与运算,结果等于其右边第二位数上的数字(设为B),如果将B往左移1位加上A,结果等于二进制的1位数相加的结果。
异或运算
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0
与运算
0 & 0 = 0
1 & 0 = 0
0 & 1 = 0
1 & 1 =1
于是可以得到
1 + 1 = 1 ^ 1+(1 & 1)<<1
1 + 0 = 1 ^ 0+(1 & 0)<<1
0 + 1 =0 ^ 1+(0 & 1)<<1
0 + 0 =0 ^ 0+(0 & 0)<<1
为什么会这样呢?
因为进行异或运算,代表两个不考虑进位的加法运算。进行与运算后在往左移动一位,代表只考虑进位的两个数相加结果。
对应两位数的二进制是否也成立呢?
例1
10+01=11
10^01=11
10&01=0
11+0<<1=11
例2
11+01=100
11^01=10
11&01=1
10+1<<1=10+10=100
通过例1、例2已经验证了我们的方法,如果不放心,还可以做更多测试验证,至于3位数、4位数等就不再验证了。
于是问题简化为 a+b=a^b+(a&b)<<1;但是此时,里面仍然包含了加法,怎么办呢?想想,如果a^b或(a&b)<<1有一个为0,是不是很好,就不需要计算加法了,那么到底哪个为0呢?肯定是进位。
代码实现如下:

/**
*思想:计算两个数不考虑进位相加的结果+考虑进位相加的结果。然后不断循环计算,直到两个数相加的进位结果为0,那么
*两个数不考虑进位相加的结果就是两个数相加的结果
*/
//非递归
function toAdd1($a,$b){
    $m=$a^$b; //获取两个数相加的结果(不包含进位)
    $n=$a&$b;// 将其向左移动一位即为两个算相加的进位
    while($n){
        $n=$n<<1;
        $tmp=$m;
        $m=$m^$n;
        $n=$tmp&$n;

    }
    return $m;
}
//递归
function toAdd2($a,$b){
    return $b?toAdd2($a^$b,($a&$b)<<1):$a;
}

减法运算

既然加法的位运算已经实现了,那么减法位运算就相对简单了,因为减去一个数,等于加上这个数的相反数,关键在于求一个数的相反数。已知一个数的相反数对于其各位取反加1。即a的相反数等于~a+1。
于是a-b=a+~b+1
于是通过程序实现如下

function toAdd2($a,$b){
    return $b?toAdd2($a^$b,($a&$b)<<1):$a;
}
function toMinus1($a,$b){
    return toAdd1($a,toAdd1(~$b,1));
}
function toMinus2($a,$b){ 
    return toAdd2($a,toAdd2(~$b,1));
}

乘法运算

原理上还是通过加法计算。将b个a相加,注意下面实际的代码。
代码如下:

//$a乘以$b等于$b$a相加
function toMultip($a,$b){
    $i=1;
    if($b==0) return 0;
    $sum=$a;
    while ( $i<$b) {
        $sum=toAdd1($sum,$a);
        $i=toAdd1($i,1);
    }
    return $sum;
}

除法运算

除法运算是乘法的逆。a最多能被多少个b减
代码如下:

//a最多能被多数个b减
function toDivision($a,$b){
    $count=0;
    while ($a >=$b) {
        $a=toMinus1($a,$b);
        $count=toAdd1($count,1);
    }
    return $count;
}

两个变量交换

function change(&$i,&$j){
    $i=$i^$j;  
    $j=$i^$j;  
    $i=$i^$j;  
}
$a=3;
$b=5;
change($a,$b);

关于交互变量,我在之前的博客里面详细讨论过了,详细描述请点击这里

<think>嗯,用户让我用Java通过位运算交换两个整数,而且不能用临时变量。首先,我得回忆一下位运算的相关知识。位运算交换变量通常用的是异或操作,因为异或有一个特性,就是同一个数异或两次会变回原来的值。比如,a ^ b ^ b 就等于a。这可能可以用来交换两个变量的值而不需要临时变量。 那具体怎么操作呢?假设有两个变量a和b。首先,我需要把a和b的异或结果存到其中一个变量里。比如,a = a ^ b。这时候,a变成了a和b的异或结果,而b还是原来的值。接下来,要让b等于原来的a的值,可以通过异或当前的a(也就是a^b)和原来的b,即b = a ^ b。这时候的表达式其实是b = (a ^ b) ^ b,根据结合律,这等于a ^ (b ^ b),而b ^ b是0,所以结果就是a。所以此时b已经变成了原来的a的值。 然后,再处理a。此时a还是a^b,而b已经是原来的a了。所以要让a等于原来的b,可以用a = a ^ b,这时候的表达式是a = (a ^ b) ^ a,也就是b ^ (a ^ a)等于b。这样,两个变量交换了。 不过,需要注意这种情况是否适用于a和b是同一个变量的情况。比如,如果a和b指向同一个内存地址的话,这时候异或可能会导致结果为0。不过,在Java中,基本数据类型的变量是按值传递的,所以如果用户传入的是同一个变量,比如调用swap(a, a),可能不会有问题?或者会导致错误的结果?例如,假设a和b实际上是同一个变量,那么第一次异或后,a会变成0,然后后续操作就会出错。所以在实际应用中,应该先判断a和b是否相同,如果相同的话就不需要交换了。不过题目可能假设用户输入的是不同的变量,所以可能不需要处理这种情况? 接下来,如何用Java实现这个呢?Java的方法参数是按值传递的,所以如果直接在方法里交换两个参数的值,实际上不会影响到调用处的变量。因此,可能需要将变量封装在对象里,或者让方法返回一个交换后的数组。但题目可能只需要在方法内部实现交换,或者要求主函数中直接操作变量? 或者,用户可能希望的是在同一个方法内,不使用临时变量,直接交换两个变量的值。比如,原本的代码可能是这样的: int a = 5; int b = 10; // 交换a和b的值,不借助临时变量 这时候,使用位运算的话,可以按照以下步骤: a = a ^ b; b = a ^ b; // 此时b变成原来的a a = a ^ b; // 此时a变成原来的b 所以,用户需要的是一个Java程序,里面包含这样的交换逻辑。例如,可能是一个函数,或者是在main方法中直接操作。 编写代码时,应该考虑测试用例,比如正数、负数、零的情况。例如,当a=3,b=4时,交换后应该是4和3。或者当a=0,b=5时,交换后正确。或者负数的情况,比如a=-2,b=3,是否能正确交换。 另外,需要注意的是,如果a和b的值相同的话,异或操作会导致结果为0。例如,如果a和b都是5,那么a ^ b是0,然后b = 0 ^5=5,a=0^5=5,所以结果还是正确的,但中间过程会有问题吗?此时交换后的结果和原来一样,所以即使不处理这种情况也没关系。 所以,Java的代码可能如下: public class SwapUsingXOR { public static void main(String[] args) { int a = 5; int b = 10; System.out.println("交换前:a = " + a + ", b = " + b); a = a ^ b; b = a ^ b; // 现在b是原来的a a = a ^ b; // 现在a是原来的b System.out.println("交换后:a = " + a + ", b = " + b); } } 这样在main方法中直接交换a和b的值。运行的话,应该输出交换后的结果。 不过,用户可能需要一个函数,但Java基本类型是值传递,所以如果要在方法中交换两个变量的值,可能需要将它们放在数组或对象中。但题目可能只需要在方法内部展示交换的步骤,并不需要实际改变外部变量。比如,题目可能只是要求写出交换的代码逻辑,而不是作为一个可调用的函数。 综上,正确的实现应该是通过三次异或操作,按照上述步骤交换变量。同时,要解释每一步的作用,让用户理解为什么这样操作能交换值。此外,需要提醒用户注意,这种方法在a和b指向同一内存地址时的问题,不过在Java基本类型的情况下,这种情况可能不会出现,除非用户自己将变量设置为同一个,但此时交换也没有意义,结果还是正确的。</think>以下是使用位运算交换两个整数值的Java实现及逐步解释: ```java public class BitwiseSwap { public static void main(String[] args) { int a = 5; int b = 10; System.out.println("交换前:a = " + a + ", b = " + b); // 位运算交换三部曲 a = a ^ b; // 步骤1:异或结果存入a b = a ^ b; // 步骤2:还原原始a值到b a = a ^ b; // 步骤3:还原原始b值到a System.out.println("交换后:a = " + a + ", b = " + b); } } ``` ### 执行流程解析(设初始值a=5,b=10) 1. **步骤1:a = a ^ b** - 计算:5 ^ 10 = 15(二进制 0101 ^ 1010 = 1111) - 此时 a=15,b=10 2. **步骤2:b = a ^ b** - 计算:15 ^ 10 = 5(1111 ^ 1010 = 0101) - 此时 a=15,b=5(原始a值) 3. **步骤3:a = a ^ b** - 计算:15 ^ 5 = 10(1111 ^ 0101 = 1010) - 最终 a=10,b=5(完成交换) ### 位运算特性说明 $$ \begin{aligned} &\text{异或性质} \\ &1. \ x \oplus x = 0 \\ &2. \ x \oplus 0 = x \\ &3. \ \text{交换律} \ x \oplus y = y \oplus x \\ &4. \ \text{结合律} \ (x \oplus y) \oplus z = x \oplus (y \oplus z) \end{aligned} $$ ### 注意事项 1. **同值陷阱**:若初始值相同(如a=5,b=5),经过异或后变量会归零 ```java a = a ^ b; // 5 ^ 5 = 0 b = a ^ b; // 0 ^ 5 = 5 a = a ^ b; // 0 ^ 5 = 5(结果未改变) ``` 2. **作用域限制**:此方法仅能直接修改方法内的局部变量,若需封装成函数,需使用对象或数组包装参数 ### 输出验证 ``` 交换前:a = 5, b = 10 交换后:a = 10, b = 5 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值