假如我们要把1、2、-127的原码补码反码表示出来
原码 | 反码 | 补码 | |
---|---|---|---|
对于任意的一个数字 | 原码就是转化成为二进制,最高位为符号为,正数为0,负数为1 | 对于正数来说,反码就是其本身;对于负数来说,反码就是除开符号位之后,全部取反 | 对于正数来说,补码就是其本身;对于负数来说,补码就是在反码的基础之上加一 |
+0 | 0000 00000 | 0000 0000 | 0000 0000 |
-0 | 1000 00000 | 1111 1111 | 0000 0000 |
1 | 0000 00001 | 0000 0001 | 0000 0001 |
-1 | 1000 00001 | 1111 1110 | 1111 1111 |
127 | 0111 1111 | 0111 1111 | 0111 1111 |
-127 | 1111 1111 | 1000 0000 | 1000 0001 |
-128 | 无 | 无 | 1000 0000 |
- 而数字在计算机里面是以补码的形式存在的,为什么要这么做呢?
如果用原码表示的话,范围是(-127,+127),其中+0和-0的码是不一样的
如果用补码表示的话,范围就变成了(-128,+127),这样就可以多表示一个数字,而且+0和-0的码是一样的
- 如果给定一个负数的二进制表示,想要知道他的十进制的值(1001 0010)
首先我们把1001 0010先取反,得到0110 1101,然后+1,得到 0110 1110,
他的十进制值为110,所以1001 0010的原值就是-110
- 可能你也会觉得很奇怪,为什么我们将一个原码表示为补码的时候是通过取反再+1,将补码返回的时候为什么还是取反+1,不是应该先-1再取反吗?
在计算机内部,计算机只能运行加法运算,而补码的一个良好的特性就是,对于负数的补码做补码运算的时候,就可以得到其对应于正数的原码
也正是因为这个特性:能让计算机进行减法的操作,其实在计算机内部还是加法操作,不过是从1-2变成了1+(-2)
如果我们用原码进行操作的话:
如果我们用补码进行操作:
- 为什么正数相加,会产生负数呢?
通过以上的理解,我们可以看出如果相加的数字超过表示的范围的话,就会向最高位进行进位,然后读取的时候就会被判断成为负数了
例如:
127(0111 1111)
+1( 0000 0001)
————————
-128(1000 0000)
- 位运算符
1)左移:
操作运算符为:<<,向左移动,右边的低位补0,高位的舍弃,将二进制看做整数,左移相当于*2
2) 无符号右移:
操作运算符为:>>>,向右移动,右边的舍弃,左边的补零
3)有符号右移:
操作运算符为:>>,向右移动,右边的舍弃,左边看最高位是什么,是1就补1,是0就补0。将二进制数看作整数,右移一位相当于除以2
- 二进制数出现0.1f0.1f=0.010000001的情况
因为二进制数不能精确的表达不是2的倍数的数字,十进制也一样,例如10/3=0.333。但是0.3333的的结果却是0.999,那么我们对于一些金钱数字需要特别精确的时候,而java的操作数不精确是常态,我们怎么办呢?
这里有两种方法:(一)先将小数转化成为整数,整数肯定是2的倍数,计算的结果是绝对正确的,然后我们再将将计算的结果转化成为小数;(二)使用十进制数,再java中是BigDecimal
这也是我们在定义金钱字段的时候为什么用的是bigdecimal而不是float和double了 - float和double浮点数在计算机内部的存储格式