2进制-16进制-补码

进制的计算

10进制

规律: 逢10进1
数字: 0 1 2 3 4 5 6 7 8 9
权(weight): 万千百十个
基数(base): 10

2进制

规律: 逢2进1
数字: 1 2
权(weight): …32 16 8 4 2 1
基数(base): 2
计算机为啥使用2进制:

  • 2进制其设备制造成本低!适合规模化生产


         * 00000000 00000000 00000000 00000000 ----> 0
         * 00000000 00000000 00000000 00000001 ----> 1
         * 00000000 00000000 00000000 00000010 ----> 2
         * 00000000 00000000 00000000 00000011 ----> 3
         * 00000000 00000000 00000000 00000100 ----> 4
         * 00000000 00000000 00000000 00000101 ----> 5
         * 00000000 00000000 00000000 00000110 ----> 6
         * 00000000 00000000 00000000 00000111 ----> 7
         * 00000000 00000000 00000000 00001000 ----> 8
	     * 111010 ---> 58
	     * 110110 ---> 54
	     * 101110 ---> 46
	     * 1101101 ---> 109
	     * 1101000 ---> 104
	     * 1111010 ---> 122
	     * 1110010 ---> 114
	     * 1100111 ---> 102
	     * 1010100 ---> 84
	     * 1000101 ---> 69
	     * 10001110 ---> 142
	     * 10010000 ---> 146
	     * 10000111 ---> 135
		 *	eg:
	     *
	     * 2进制简单计算技巧:
	     * 	 1  0   0  1 0  0  0 0
	     * 	128 64 32 16 8  4  2 0
Integer.parseInt()
将10进制字符串转换为2进制整数 int

Integr.toString()
将2进制数字 int 转换为10进制字符串给人看

总结:
Java 能够处理10进制全部依赖于Integer类

代码块:
for (int i = 0; i <= 150; i++) {
       System.out.println(
       Integer.toBinaryString(i)
    );
}
16进制

16进制用于缩写 (简写) 2进制

2进制书写繁琐, 复杂, 易错; 由于16进制的基数是
2的4次幂,所以16进制可以实现2进制的缩写,其中
每4位2进制可以缩写为1位16进制;

如何缩写?
从2进制最低位开始, 每4位2进制可以缩写为1位16进制数字

     * 2进制与16进制
     * Java 7 支持直接书写2进制字面量, 以0b开头
     * Java 7 支持直接书写16进制字面量, 以0X开头
     * 0000     0             0111 1001 1101 1111 0110 1011 0010 1011  79DF6B2B
     * 0001     1              7     9    D    F    6    B    2    B
     * 0010     2             1011 0010 1101 0110 0010 1101 0110 1110  B2D62D6E
     * 0011     3               B    2    D    6   2     D    6    E
     * 0100     4             1011 1010 1110 1110 0001 1011 0101 1101  BAEE1B5D
     * 0101     5               B   A    E    E    1    B     5    D
     * 0110     6             1101 1011 1100 0111 0000 0111 1011 0110  DBC707B6
     * 0111     7               D   B    C    7     0    7   B    6
     * 1000     8             1001 1110 0110 0011 1100 1011 0110 1010  9E63CB6A
     * 1001     9               9    E    6    3    C    B    6    A
     * 1010     A             1011 1100 1001 1001 0110 1010 1110 1010  BC996AEA
     * 1011     B               B    C    9    9    6    A    E    A
     * 1100     C             1011 0101 0100 0011 1111 0100 1111 0111  B543F4F7
     * 1101     D               B    5    4    3    F    4    F    7
     * 1110     E             0110 1011 1011 1001 1110 1000 1001 0010  6BB9E892
     * 1111     F               6    B    B    9    E    8    9    2
代码块:
@Test
public void test01() throws Exception{
   int num = 0X6BB9E892;
   System.out.println(
           Integer.toBinaryString(num)
   );
}
补码

什么是补码

  • 计算机中用于处理负数的一种编码规则, 其核心思想是将固定位数

以4位2进制为例子讲解编码规则:

  1. 计算时候保持4位数不变, 超出的4位数的数据自动溢出, 不要了;
  2. 高位为0的一半作为正数, 高位为1的一半作为负数;
  3. 计算时候, 将10进制数 (包含负数) 转换为底层2进制补码计算,
    计算结果也是2进制补码, 再利用 API 转换为10进制 (包含负数) 显示;
  4. 补码是环形编码, 最大值和最小值相接, 相差1
  5. (巧合) 正数编码和负数编码互补对称, 故称为: 补码
    计算补码的简单技巧

11111111111111111111111111101110
0000000000000000000000010001
0000000000000000000000010010
在这里插入图片描述

2进制取反 代码块:
int num = -18;
int num02 = ~num + 1;

System.out.println(
        Integer.toBinaryString(num)
);// 11111111111111111111111111101110
System.out.println(
        Integer.toBinaryString(~num)
);// 00000000000000000000000000010001
System.out.println(
        Integer.toBinaryString(~num + 1)
);// 00000000000000000000000000010010
 int / long 负数的编码的算法技巧
 -(...  8 4 2 2)
 1 0 0 1 - - - >(-7)
int > -1 > (11111111111111111111111111111111)
 11111111111111111111111111101110 - - - > -18  > (num)  
 00000000000000000000000010001 - - - > 17  >(~num)
 00000000000000000000000010010  - - - > 18 >(~num+1)
运算符
运算规则 (逻辑乘法): 有0则0
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

约定: 将两个2进制数数字对齐, 应位子上的数字进行与运算
举个例子:
b: bit
1int = 8byte=32bit
--------- b1 ---------- b2 -------- b3 -------- b4 ------
n = 10101010 11110101 10101010 11001111
m = 00000000 00000000 00000000 11111111 ------->掩码(Mask 面具)
b4 = n&m = 00000000 00000000 00000000 1101111
如上案例, 是掩码计算: 其结果k中存储的数据是数字n的最后8位数
案例:
int n = 0xaaf5aacf;
int m = 0xff;
int b4 = n & m;

16进制 代码块:
 @Test
    public void test03() throws Exception {
        /**
         * 10101010 11110101 10101010 11001111
         * 00000000 00000000 00000000 11111111
         * 00000000 00000000 00000000 11001111
         *
         */
        int n = 0xaaf5aacf;
        int m = 0xff;
        int b4 = n & m;
        System.out.println(
                Integer.toBinaryString(n)
        );
        System.out.println(
                Integer.toBinaryString(m)
        );
        System.out.println(
                Integer.toBinaryString(b4)
        );
    }
16进制 Result:
10101010111101011010101011001111
11111111
11001111
>>> 右移位运算

运算规则:

* 将数字的每个位向左侧移动, 移动后左侧多出的位自动溢出 (舍弃), 右侧补充0
* 例子:                                b1      b2       b3       b4                                                     
* n =                              01001111 10100110 11110001 10011110
* m = n >>> 1                      001001111 10100110 11110001 1001111 (0) 舍弃
* k = n >>> 2                      0001001111 10100110 11110001 100111 (10) 舍弃
* b1 = (n >>> 24) & 0xff;          00000000 00000000 00000000 01001111 (10100110 11110001 10011110)舍弃
* b2 = (n >>> 16) & 0xff;          00000000 00000000 00000000 10100110 (11110001 10011110)舍弃
* b3 = (n >>> 8) & 0xff;           00000000 00000000 00000000 11110001 (10011110)舍弃
* b4 = n & 0xff;                   00000000 00000000 00000000 10011110
 或运算 '|' 
 基本规则:逻辑加法, 有1则1 
 0 | 0 = 0
 0 | 1 = 1
 1 | 0 = 1
 1 | 1 = 1
左移位计算 底层实现原理
将两个2进制数对齐位置, 对应的位置计算 "或"
举个例子:
n =        00000000 00000000 00000000 11011101
m =        00000000 00000000 11011101 00000000
k = n |m   00000000 00000000 11011101 11011101 

b1 = 00000000 00000000 00000000 01001111
b2 = 00000000 00000000 00000000 10100110
b3 = 00000000 00000000 00000000 11110001
b4 = 00000000 00000000 00000000 10011110

(b1 << 24) 01001111 00000000 00000000 00000000 
(b2 << 16) 00000000 10100110 00000000 00000000 
(b3 << 8)  00000000 00000000 11110001 00000000
b4         00000000 00000000 00000000 10011110

n = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
       b1       b2       b3       b4         
n = 01001111 10100110 11110001 10011110
b1 = 0x4f;
b2 = 0xa6;
b3 = 0xf1;
b4 = 0x9e;
n = 0x4fa6f19e;

如上运算的意义: m和n两个拼接以后为k
案例:
int n = 0xdd;
int m = 0xdd00;
int k = n | m;

左移位计算 代码块:
 @Test
    public void test05() throws Exception {
        int b1 = 0x4f << 24;
        int b2 = 0xa6 << 16;
        int b3 = 0xf1 << 8;
        int b4 = 0x9e;

        int n = b1 | b2 | b3 | b4;// n = 0x4fa6f19e;

        System.out.println(
                Integer.toBinaryString(n)
        );// 01001111 10100110 11110001 10011110

        System.out.println(
                Integer.toBinaryString(b1)
        );// 01001111

        System.out.println(
                Integer.toBinaryString(b2)
        );// 10100110

        System.out.println(
                Integer.toBinaryString(b3)
        );// 11110001

        System.out.println(
                Integer.toBinaryString(b4)
        );// 10011110

    }

左移位计算 Result:
01001111 10100110 11110001 10011110
10011110 00000000000000000000000
10100110 0000000000000000
11110001 00000000
10011110

位移计算的数学意义
10进制左移动小数点计算: 
//    	  18319.
// 	     183190. 扩大10倍
//	   18319100. 扩大100倍

如果小数点不动, 数字向左移动一次, 扩大10倍

2进制左移位小数点计算:
//        110010.	50
//		 1100100.	100    扩大2倍
//      11001000.   200    扩大4倍
如果小数点不动, 数字向左移动一次, 扩大2倍

2进制右移位小数点计算:
//        11001.	25     缩小2倍
//         1100.	12     缩小4倍, 小方向取整数


案例:
int n = 50;
int m = n << 1;	100	// 扩大2倍
int k = n << 2;	200	// 扩大4倍
int o = n >> 1;	25	// 缩小2倍
int p = n >> 2;	12	// 缩小4倍

>>> 和 >> 的区别
'>>>' 逻辑右移位: 将2进制数字向右移位, 低位自动溢出舍弃, 高位补0
'>>' 数学右移位: 将2进制数字向右移位, 低位自动溢出舍弃,正数补0, 负数补1

举个例子:
n = -50                 11111111 11111111 11111111 11001110             -50
m = n >> 1              111111111 11111111 11111111 1100111 (0)舍弃     -25
k = n >> 2              1111111111 11111111 11111111 110011 (10)舍弃    -13 小方向取整数
g = n >>> 1             011111111 11111111 11111111 1100111(0)舍弃      比最大值少24

案例:
int n = -50;     -50
int m = n >> 1;  -25
int k = n >> 2;  -13 小方向取整数
int g = n >>> 1; 比最大值少24

如上结果说明:
 '>>' : 计算是数学除法
'>>>' : 不是数学除法, 就是逻辑上将数组向右移动, 不区分正负数;

向右移动有符号问题, 所以有两个运算符号, 左移动只有一个符号 '<<'

使用建议: 
如果替代除法(2的整数幂) : '>>'
如果是拆分数据, 就是实现数位的移动 : '>>>'

经典面试题: 
n * 16 可以替换为 (n << 4) (16 = 2^4)
size / 2 (size > 0)  可以替换为 (size >> 1)

好的,让我们来了解一下 `-A0` 和 `A0` 的16进制补码表示。 ### 一、基础知识回顾 **1. 补码的概念** - **正数的补码**:对于无符号整数或正值来说,在二进制下其原码、反码和补码都是相同的。 - **负数的补码**:对于有符号负值,则需要通过求取该数值绝对值对应的二进制形式,并对其进行按位取反再加1的操作得到最终结果作为补码表达式。 **2. 十六进制转二进制** - 每一位十六进制数字对应四位二进制数字。例如,“A”代表“10”,转换成二进制就是`1010`;而“F”则是`1111`。 --- ### 二、计过程详解 #### (1)解析给定数据“A0” - 首先将 “A0”的每个字符分别转化为4位二进制串: - \( A = (10)_{10} \rightarrow (1010)_2\) - \( 0 = (0000)_2\) 因此我们得出\( A0_{16}\)= `(1010 0000)` 或简写作`(1010_0000)_2` #### (2)对"A0"求相反数(-A0),并获得它的8位机器字长下的补码表示: ##### 步骤① 将 "A0" 转换为十进制以便处理 \[A0_{16}=160_{10}\] 因为这是一个带负号的情况,所以我们现在讨论的是 "-160" ##### 步骤② 然后确定它在一个特定范围内的补码形式(假设采用常见的8比特系统): 首先找到+160在8bit情况下的溢出问题——实际上由于超过了所能直接表述的最大非负整数(\[7FH=127D\])所以这里应该被视为超出界限; 但在某些场合如学习目的允许的话,我们可以假想一下如果真的存在这样的环境会怎么展示这个值: 1. 先写出160的8位二进制表示(虽然现实中无法存储),即`1010 0000` 2. 因为我们是在做减法运(相当于加上一个大得足以翻转最高有效位MSB的量级),于是就等价于对上述序列每一位都做了反转操作后再累加1: ```text 原始值 : 1010 0000 反码 : 0101 1111 加上1后的补码: 0110 0000 ``` 综上所述, - 对应到具体的八位系统内实际呈现出来的效果可能是非法状态或者循环绕回到某个合法区间,比如这里的-(96),但这取决于具体硬件架构如何设计以及是否支持这种超界输入场景。 > 注意:通常情况下,当涉及到计机内部的数据表示时,尤其是在固定宽度的寄存器环境中,超过最大容量的部分会被截断或导致其他异常行为。所以上面所说的"-160"并不真正存在于标准8位体系结构中。 ### 总结 对于正常的8-bit环境下: - `"A0"` 的16进制补码还是自身(`A0`); - "`-A0`" 从理论上讲应该是`"(FF-) + (逆序+A)"`, 也就是`0x60`(即十进制96). 但是要注意这只是一个理论性的解释,在真实的编程实践中你应该依据语言特性及目标平台的具体规则来进行正确的编码工作!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值