Skip to content

二进制

位运算符

符号描述运算规则
&两个位都为 1 时,结果才为 1
|两个位都为 0 时,结果才为 0
^异或两个位相同为 0,相异为 1
~取反0 变 1,1 变 0
<<左移各二进位全部左移若干位,高位丢弃,低位补 0
>>右移各二进位全部右移若干位,低位丢弃,高位补 0

&与运算(两个位都为 1 时,结果才为 1 )

js
0&0=0
0&1=0
1&1=1

//  判断奇偶(如果最低位是1,则是偶数,后面都是2的倍数)
12&1=0 // 偶
13&1=1 // 奇

|或运算(两个位都为 0 时,结果才为 0)

js
0|0=0
0|1=1
1|1=1
// 或0取整
100.11|0=100
// 或自身等于自身
235|235 = 235

^异或运算(两个位相同为 0,相异为 1)

js
0^0=0
1^1=0
1^0=1

// 异或自身等于0(归零律)
100^100=0
// 异或0等于自身(恒等律)
100^0=100

// 结合律
100^0=100
// 与顺序无关
a^b^c==c^b^c


// 数据交换
let a = 10;
let b = 20;

a = a ^ b;
b = b ^ a;
a = a ^ b;
console.log(a);
console.log(b);
[b,a]=[a,b]

~取反运算( 0 变 1,1 变 0)

  • 取反在减一
js
~0=1
~1=0

~5=-6

位移运算

  • 1、<< 左移
  • 2、>>>无符号右移
  • 3、>>有符号位移

"<<"运算符

  • 运行原理:"<<"运算符执行左移位运算。在移位运算过程中,符号位始终保持不变。如果右侧空出位置,则自动填充为 0;超出 32 位的值,则自动丢弃。
js
console.log(5 << 2); //20

img

">>"运算符

  • 运行原理:">>"运算符执行有符号右移位运算。与左移运算操作相反,它把 32 位数字中的所有有效位整体右移,再使用符号位的值填充空位。移动过程中超出的值将被丢弃。
js
conosle.log(1000 >> 8); //3

img

js
console.log(-1000 >> 8); //-4

img

">>>"运算符

  • 运行原理:">>>"运算符执行五符号右移位运算。它把无符号的 32 位整数所有数位整体右移,无符号右移与有符号右移运算的结果是相同的
js
console.log(1000 >> 8); //返回值3
console.log(1000 >>> 8); //返回值3

console.log(-1000 >> 8); //返回值 -4
console.log(-1000 >>> 8); //返回值 16777212

img

二进制权限控制

  • 假设我们需要设计一个读、写、执行三种权限,每一个可以任意组合,我们可以通过二进制来控制
js
let r = 1 << 0; // 1(读)
let w = 1 << 1; // 2(写)
let x = 1 << 2; // 4(执行)
// 或(|)运用符,一个为1则为1
let add = r | w | x; // 7(所有权限)

// 给张三加读写权限
let zhangsan = r | w;
console.log(zhangsan & r);
console.log(zhangsan & w);

// 取消张三可读权限
// 异或两个位相同为 0
zhangsan = zhangsan ^ r;
console.log(zhangsan & r);

0.1+0.2!=0.3

  • 1、因为在计算的时候十进制会转成二进制
  • 2、小数在转化二进制的时候会乘 2,取出整数部分,有剩余的小数部分继续乘 2
  • 3、0.1 / 0.2 转换的时候会进入死循环,尾数超过 52 位会被丢弃,导致计算不正确
js

0.1转化成二进制的算法:

0.1*2=0.2======取出整数部分0

0.2*2=0.4======取出整数部分0

0.4*2=0.8======取出整数部分0

0.8*2=1.6======取出整数部分1

0.6*2=1.2======取出整数部分1

0.2*2=0.4======取出整数部分0

0.4*2=0.8======取出整数部分0

0.8*2=1.6======取出整数部分1

0.6*2=1.2======取出整数部分1

接下来会无限循环

0.2*2=0.4======取出整数部分0

0.4*2=0.8======取出整数部分0

0.8*2=1.6======取出整数部分1

0.6*2=1.2======取出整数部分1

8进制转二进制

  • 8进制0-7,0作为开头
  • 一个八进制,占三位
js
// 八进制对应的二进制表现方式
let a = 016 // 001 110
let b = 0123 // 001 010 011

10进制转二进制

  • 整数部分: 除 2 取余,直到商为 0,最先得到的余数是最低位,最后得到的余数是最高位.
  • 小数部分: 乘 2 取整,直到积为 0 或者达到精度要求为止,最先得到的整数是高位
  • 例如 (7.75)10=(111.11)2
  • 高位在左,低位在右 Alt

16进制转二进制

  • 16进制0-9、字母A到F(或a~f)->10-15,0x作为开头
  • 一个16进制,占四位
js
// 八进制对应的二进制表现方式
let a = 0x1a // 0001 1010
let b = 0x1f // 0001 1111

2进制转8进制

  • 三个位代表一个8进制
js
let a = 001110 // 001 110 => 016
let b = 001010011 // 001 010 011 => 0123

2进制转10进制

TIP

  • 负次计算: 一个数的负几次方就是这个数的几次方的倒数。
    • 2的负1次方=2的1次方分之一=1/2
    • 3的负2次方=3的2次方分之一=1/9
    • 4的负2次方=4的2次方分之一=1/16
  • 方法: 按权展开,加权求和,以(111.11)2 为例 Alt

2进制转16进制

  • 四个位代表一个16进制
js
let a = 00011010 // 0001 1010 => 0x1a
let b = 00011111 // 0001 1111 => 0x1f

计算机中的数据

  • 一个字节有 8 位(11111111)二进制,一个 bit 等于一位(1)二进制,

    数据

  • 1、数值数据
    • 无符号数据(没有正负符号为)
    • 有符号数据(有正负符号为)0 为正,1 为负
  • 2、数值数据
    • 文字
    • 图像

无符号数据的表示(原码)

  • 原码: 3 个 bit(111)能表示 8 个数 01234567Alt

有符号数据的表示(原码)

  • 原码: 3 个 bit 能表示 8 个数 +0+1+2+3-0-1-2-3
  • 符号: 用 01 表示号,放在数值的最高位 Alt

有符号数据(反码)

  • 反码:正数不变,负数的除符号位外取反Alt

有符号数据(补码)

  • 补码:正数不变,负数在反码的基础上加 1Alt

原码、反码、补码

TIP

  • 计算机里的数都是补码的形式
  • 正数的补码、反码和原码一样

    • 例如:7
    • 原码:0111
    • 反码:0111
    • 补码:0111
  • 负数:通过原码求补码的转换方法:符号位不变每个数值位求反(反码),末位加 1

    • 例如:-7
    • 转为二进制原码:1111
    • 从原码转为反码:1000
    • 从反码转为补码:1001
c
#include <stdio.h>

int main() {
    unsigned char ch;
    // 计算机都是以补码的形式计算
    // 00000001 // 原码
    // 11111110 // 反码(原码取反)
    // 11111111 // 补码(反码+1)
    ch = -1;
    printf("ch=%d %c\n", ch, ch); // 255 %c ASCII 没有对应的255所以是乱码
    return 0;
}

IEEE754标准

  • JavaScript采用的是双精度(64位)
  • 符号位决定了一个数的正负,指数部分决定了数值的大小,小数有效位部分决定了数值的精度
  • 一个数在 JavaScript 内部实际的表示形式 (-1)符号位1.有效位2指数位
  • 精度最多53个二进制位, -(253-1)到253-1
  • 指数部分最大值是 2017(211-1),分一半表示负数,JavaScript能够表示的数值范围是21024~2-10

AltAlt