二进制与位运算

1、正数怎么用二进制表达

        现在以四位为例,四位只能表示表示 -8 ~ 7,一共16个数(2^4)。java语言中32位的int类型和64位的long类型可以表示更多数。

        以四位为例,正数的第一位一定是0,比如十进制的6在二进制中就是0110。

2、负数怎么用二进制表达

        还是以四位为例,负数的第一位一定是1。一个负数(比如-6)转换成一个二进制难以直接写出,但是在这里只需要记住一个原则:一个数取反再加1就是他的相反数,就很好解决了。

        将 -6转换成一个二进制,我们可以先写出6的二进制形式,再取反加一,就是-6的二进制形式。6的二进制形式是0110,取反则为1001,再加一则为1010,故1010就是二进制的-6。

        如果反过来,我们知道负数的二进制形式,怎么知道它的十进制形式呢?还是一样,取反加一获得他的相反数就可以。比如1010,第一位是1,肯定是个负数,我们要知道具体是哪个负数,先取反得到0101,再加一得到0110,0110在十进制中表示6(这个可以明显看出),故1010就表示 -6。

        扩展开来,无论是32位还是64位的表示形式,都可以用一样的原则。

        但对于整数最小值,一个数取反再加1就是他的相反数这个原则不适用,比如1000,表示-8,4位表示的最小的数就是-8,将1000取反加一还是1000,是-8本身,并不能得到8,这是因为4位只能表示正数-8~7,8不在这个范围中。

3、常见的位运算(|,&,^,~,<<,>>,>>>)

        |:位运算或。0110 | 1001 = 1111,对每一位取或运算,相同位置只要至少有一个1结果就是1,否则为0

        &:位运算与。0111 & 1001 = 0001,对每一位取与运算,相同位置必须全是1结果才是1,否则为0

        ^:位运算亦或。0111 ^ 1001 = 1110,对每一位取亦或运算,相同位置相同则为0相异则为1。

        ~:取反运算。~0111 = 1000, 对每一位取反。

        <<:左移运算。这里拿32位举例,对于正数:

                                x = 00000000000000000000000000001010,

                                x << 1 = 00000000000000000000000000010100,

                整体向左移动一位,右边缺的用0补齐。

                对于负数:

                                y = 10000000000000000000000000001010,

                                y<<1 = 10000000000000000000000000010100,

                整体向左移动一位,右边缺的用0补齐,左边继续是以1开头。

        >>和>>>:右移运算。对于非负数,>>和>>>都是一样的效果,比如正数:

                                x = 00000000000000000000000000001010,

                                x>>1 = x>>>1 =00000000000000000000000000000101。

                对于负数,负数做>>运算,整体向右移动,左边用1补齐,负数做>>>运算,整体向右移动,左边用0补齐。例如

                                y = 11110000000000000000000000000000,

                                y >> 2 = 11111100000000000000000000000000,

                                y>>>2 = 00111100000000000000000000000000。

                因此对于非负数,有一个规律:非负数>>i,等同与除以2的i次方。非负数<<i,等同于乘以2的i次方。

4、|、&与||、&&的区别

        区别1|和&是位运算,||和&&是逻辑运算,||和&&两端只能链接boolean类型,比如4||5,1&&2这种写法都是错误的。

        区别2:通常来讲,||和&&的效率更高,比如,对于a&&b,a若位假,则不会判断b,直接返回假,但对于a&b,即使判断a为假后,也会判断b,下面用一个例子证明。

public class Bit {
    public staic void main(String[] args) {
        returnTrue() | returnFalse();     //进入了returnTrue,进入了returnFalse
        System.out.println("test1测试结束");

        returnFalse() & returnTrue();    //进入了returnFalse,进入了returnFalse
        System.out.println("test2测试结束");

        returnTrue() || returnFalse();    //进入了returnTrue,没有进入returnFalse
        System.out.println("test3测试结束");

        returnFalse() && returnTrue();    //进入了returnFalse,没有进入returnTrue
        System.out.println("test4测试结束");
        
    }
    public staic boolean returnTrue(){
        System.out.println("进入了returnTrue函数");
        return True;
    }
    public staic boolean returnFalse(){
        System.out.println("进入了returnFalse函数");
        return False;
    }
}

5、java中一个打印二进制的函数

        实现输入一个整型int,可以输出该整型的二进制形式。

public class BinarySystem {
    pubilic static void main(String[] args) {
        int a = 6;         

        int b = 0b0110;    //这是6的java二进制表示法

        printBinary(a);    //输出00000000000000000000000000000110
        printBinary(b);    //输出00000000000000000000000000000110
    }

    public static void printBinary(int num) {
        for(int i = 31; i >= 0; i--) {
            System.out.print((num & (1 << i)) == 0 ? "0": "1");

        //为什么可以这样写
        //以6为例,6的二进制形式为0110,进入第一个循环时,0110 & 1000 = 0,因此打印0;进入第二个循环时,0110 & 0100 = 0100,不等于0,因此打印1,以此类推,最终打印出0110
        }
        System.out.println();
    }
}

   6、为什么这样设计二进制,为什么负数的二进制设计如此复杂?

        这主要是为了加法逻辑的合理性,接下来解释一下为什么这样设计二进制会使得加法逻辑合理。

        以-5+7为例,-5的二进制形式为1011,7的二进制形式为0111,相加得0010,也就是2。注意这里发生了溢出,但计算结果最终还是对的,这就是二进制的精妙之处!

  • 38
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值