在计算机中,除了二进制,比较常用的还有八进制和十六进制。

常用进制

  1. 二进制:只有0,1两个数,满2进1,以0b开头表示
  2. 八进制:0-7表示,满8进1,以数字0o开头表示
  3. 十进制:0-9表示,满10进1
  4. 十六进制:0-9 A-F表示,满16进1,以数字0x开头表示

Integer literals in golang

在golang中使用二进制和十六进制

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package main

import "fmt"

func main() {
    b := byte(0b00010100)
    fmt.Printf("%08b %02x\n", b, b)
    x := byte(0x14)
    fmt.Printf("%08b %02x\n", x, x)
}

进制转换

十进制转二进制

整数部分,把十进制数不断执行除 2 操作,直至商数为 0。读余数从下读到上,即是二进制的整数部分数字。小数部分,则用其乘 2,取其整数部分的结果,再用计算后的小数部分依此重复计算,算到小数部分全为 0 为止,之后从上到下,读所有计算后整数部分的数字,即为二进制的小数部分数字。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
将33.25转化为二进制数
整数部分:
33/2=16 ......1
16/2=8  ......0
8/2=4   ......0
4/2=2   ......0
2/2=1   ......0
1/2=0   ......1
小数部分:
0.25*2=0.5  0
0.5*2=1     1

即33.25 = 100001.01 其他进制原理相同。

二进制转十进制

二进制数转换为十进制数,只需将每个位的值,乘以 2^i 次即可,其中 i 为当前位的位数,个位的位数为 0。

1
2
3
将二进制数 11010.01 转换为十进制数
11010.01=1*2^4+1*2^3+0*2^2+1*2^1+0*2^0+0*2^(-1)+1*2(-2)
        =26.25

即 11010.01 = 26.25 其他进制原理相同。

二进制/八进制/十六进制间的相互转换

一个八进制位可以用 3 个二进制位来表示(因为 2^3 =8),一个十六进制位可以用 4 个二进制位来表示(2^4 = 16),反之同理。

二进制 -> 八进制:从右往左,每三位转成八进制;111101的八进制就是75:7=12^2+12^1+12^0,5=12^2+1*2^0

二进制 -> 十六进制:从右往左,每四位转成十六进制;11111011的十六进制就是FB (1111=16=F,1011=11=B)

八进制 -> 二进制:依次将每一位转为3位的二进制

十六进制 -> 二进制:依次将每一位转成4位的二进制

在golang中将十进制数字转换为其他进制(比如二进制、八进制或者十六进制)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main
 
import (
    "fmt"
    "strconv"
)
 
func main() {
    decimal := int64(10) // 十进制数字
    binary := strconv.FormatInt(decimal, 2)   // 转换成二进制
    octal := strconv.FormatInt(decimal, 8)     // 转换成八进制
    hexadecimal := strconv.FormatInt(decimal, 16) // 转换成十六进制
 
    fmt.Println("Binary:", binary)
    fmt.Println("Octal:", octal)
    fmt.Println("Hexadecimal:", hexadecimal)
}

// output:
// Binary: 1010
// Octal: 12
// Hexadecimal: a

在golang中将其他进制(比如二进制、八进制或者十六进制)转换为十进制数字

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main
 
import (
    "fmt"
    "strconv"
)
 
func main() {
    binaryString := "1010"    // 二进制字符串
    octalString := "12"       // 八进制字符串
    hexadecimalString := "a"  // 十六进制字符串
 
    decimalFromBinary, _ := strconv.ParseInt(binaryString, 2, 64)      // 从二进制转换为十进制
    decimalFromOctal, _ := strconv.ParseInt(octalString, 8, 64)        // 从八进制转换为十进制
    decimalFromHexadecimal, _ := strconv.ParseInt(hexadecimalString, 16, 64) // 从十六进制转换为十进制
 
    fmt.Println("Decimal from Binary:", decimalFromBinary)
    fmt.Println("Decimal from Octal:", decimalFromOctal)
    fmt.Println("Decimal from Hexadecimal:", decimalFromHexadecimal)
}

// output
// Decimal from Binary: 10
// Decimal from Octal: 10
// Decimal from Hexadecimal: 10

位运算

位运算就是基于整数的二进制表示进行的运算。由于计算机内部就是以二进制来存储数据,位运算是相当快的。

基本的位运算共 6 种,分别为按位与、按位或、按位异或、按位取反、左移和右移。

原码、反码、补码

原码、反码、补码的产生过程就是为了解决计算机做减法和引入符号位的问题。

原码:用最高位表示符号位,其他位存放该数的二进制的绝对值。 反码:正数的反码还是等于原码;负数的反码就是它的原码除符号位外,按位取反。 补码:正数的补码等于它的原码;负数的补码等于反码+1

1)对于有符号而言:

  • 二进制的最高位是符号位:0表示正数,1表示负数
  • 正数的原码、反码、补码都一样
  • 负数的反码=除符号位以外的取反
  • 负数的补码=反码+1
  • 0的反码、补码都是0
  • 在计算机运算的时候,都是以补码的方式进行运算的

与、或、异或

按位&:两位全为1,则为1,否则为0

按位|:两位中有一个为1,则为1,否则为0

按位^:两位一个为1,一个为0,结果为1,否则为0

例如: 2的原码、反码和补码都是:0000 0010    3的原码、反码和补码都是:0000 0011

则有 2 & 3 = 0000 0010 = 2    2 | 3 = 0000 0011 = 3    2 ^ 3 = 0000 0001 = 1

取反

再看-2的原码:1 000 0010,其反码为1 111 1101,补码为1 111 1110

则有-2^2 =1 111 1110 ^ 0 000 0010 = 1 111 1100,必须转换成原码才能知道它的值,则有:结果-1再取反

1 111 1100 - 1 = 1 111 1011 符号位不变再取反 1 000 0100,则-2^2的值是:-4

左移和右移

>>:符号位不变,低位溢出,用符号位补高位

<<:符号位不变,低位补0

参考