Java位运算 常见的位运算

[Q&A] 位运算支持的类型

位运算符中 ,操作数只能为整型字符型数据。

[Q&A] 位运算符号

在这里插入图片描述

按位与(&)

同1则1 → 类比Java的&&,都为true时才为true

操作数10011
操作数20101
按位与0001

按位或(|)

有1则1 → 类比Java的||,有一个为true则为true

操作数10011
操作数20101
按位或0111

按位取反(~)

取反 → 类比Java的!,逻辑取反

操作数01
按位非10

按位异或(^)

异为1同为0 → 类比两条数据使用比较工具进行比较,不同数据会被高亮

异或,英文为exclusive OR,缩写成xor,也叫半加运算:异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0,这些法则与加法是相同的,只是不带进位,所以异或常被认作不进位加法。

操作数10011
操作数20101
按位异或0110

左位移(<<)

溢出截断,低位补0

在这里插入图片描述

右位移(>>)

溢出截断,高位补符号位

在这里插入图片描述

无符号右移(>>>)

溢出截断,高位补0
在这里插入图片描述


总结

按位取反的理解

 2进制    -1补码:11111111111111111111111111111111

 2进制    14原码:00000000000000000000000000001110
 2进制    14反码:00000000000000000000000000001110
 2进制    14补码:00000000000000000000000000001110
 
 2进制   -14原码:10000000000000000000000000001110
 2进制   -14反码:11111111111111111111111111110001
 2进制   -14补码:11111111111111111111111111110010

如果 x + y = 11111111,可得 x 和 y 互为按位取反的关系,不分正负时11111111是2^N-1。如分正负时,11111111是-1
负数绝对值 和 负数反码 互为按位取反的关系 等价 负数绝对值 + 负数反码 = Mod(2^N) -1
负数绝对值 + 负数补码 = Mod(2^N) 推导出 负数补码 = 负数反码 + 1
原码,反码,补码之间的关系?
二进制里 减一取反取反加一 等价
二进制里为什么减一取反和取反加一等价?

取反的 3 种方式

 2进制    14补码:00000000000000000000000000001110

 2进制    ~1411111111111111111111111111110001
 2进制  14^-111111111111111111111111111110001
 2进制  -14-111111111111111111111111111110001
 2进制   -14补码:11111111111111111111111111110010
 
 2进制   ~-1400000000000000000000000000001101
 2进制 -14^-100000000000000000000000000001101
 2进制 --14-100000000000000000000000000001101
private static void test(int num) {
    System.out.println("10进制 " + proFillSpace("输入数:") + num);
    System.out.println(" 2进制 " + proFillSpace("-1补码:") + Integer.toBinaryString(-1));
    System.out.println(" 2进制 " + proFillSpace(num + "补码:") + proFillZero(Integer.toBinaryString(num)));
    System.out.println(" 2进制 " + proFillSpace(-num + "补码:") + proFillZero(Integer.toBinaryString(-num)));
    System.out.println(" 2进制 " + proFillSpace("~(" + num +")" + " ☞") + proFillSpace(num) + "按位取反: " + proFillZero(Integer.toBinaryString(~num)));
    System.out.println(" 2进制 " + proFillSpace("(" + num + ")" +"^-1 ☞") + proFillSpace(num) + "按位取反: " + proFillZero(Integer.toBinaryString(num ^ -1)));
    System.out.println(" 2进制 " + proFillSpace("-1-(" + num + ")" + " ☞") + proFillSpace(num) + "按位取反: " + proFillZero(Integer.toBinaryString(-1 - num)));
}
private static String proFillZero(String str) {
    if (str.length() >= 32) {
        return str;
    }
    return proFillZero("0" + str);
}
private static String proFillSpace(Object i) {
    String str = String.valueOf(i);
    return proFillSpace2(str);
}
private static String proFillSpace2(String str) {
    if (str.length() >= 10) {
        return str;
    }
    return proFillSpace2(" " + str);
}

10进制       输入数:14
 2进制      -1补码:11111111111111111111111111111111
 2进制      14补码:00000000000000000000000000001110
 2进制     -14补码:11111111111111111111111111110010
 2进制    ~(14)14按位取反: 11111111111111111111111111110001
 2进制  (14)^-114按位取反: 11111111111111111111111111110001
 2进制  -1-(14)14按位取反: 11111111111111111111111111110001

与运算(&)的用途

或运算(|)的用途

异或运算(^)的用途

左位移运算(<<)的用途

右位移运算(>>)的用途

运算符组合运算场景

取绝对值

(a^(a>>31))-(a>>31) 取反加1
(a+(a>>31))^(a>>31)1取反
# 正数
System.out.println((0 ^ (0 >> 31)) - (0 >> 31));// 0
System.out.println((5 ^ (5 >> 31)) - (5 >> 31));// 5
System.out.println((6 ^ (6 >> 31)) - (6 >> 31));// 6
System.out.println((7 ^ (7 >> 31)) - (7 >> 31));// 7

# 负数
System.out.println((-1 ^ (-1 >> 31)) - (-1 >> 31));// 1
System.out.println((-5 ^ (-5 >> 31)) - (-5 >> 31));// 5
System.out.println((-6 ^ (-6 >> 31)) - (-6 >> 31));// 6
System.out.println((-7 ^ (-7 >> 31)) - (-7 >> 31));// 7

4字节时,右移31操作可以取得任何整数的符号位
任何正数右移31后只剩符号位0,,溢出的31位截断,空出的31位补0,最终结果为0
任何负数右移31后也只剩符号位1,溢出的31位截断,空出的31位补符号位1,最终结果为-1

int[] arr = {-3, -2, -1, 0, 1, 2, 3};
for (int i : arr) {
    abs1(i);
}
// 3 2 1 0 1 2 3 

for (int i : arr) {
    abs2(i);
}
// 3 2 1 0 1 2 3 

private static void abs1(int num) {
    int i = (num ^ (num >> 31)) - (num >> 31);
    System.out.print(i + " ");
}
private static void abs2(int num) {
    int i = (num + (num >> 31)) ^ (num >> 31);
    System.out.print(i + " ");
}

参考:Java位运算原理及使用讲解

找出没有重复的数 (使用起来有太多局限,非通用)

public static int find(int[] nums){
    int tmp = nums[0];
    for(int i = 1;i < nums.length; i++)
        tmp ^= arr[i];
    
    return tmp;
}

参考:

几种常见的位运算
C语言位运算的妙用你知道多少?
位运算的妙用
位运算用法
位运算详解
https://imageslr.com/2019/12/11/data-lab-2.html

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值