本文自问自答地从一个问题,介绍 Golang 中的数字类型和位操作。
Golang 中数值类型的取值范围
uint8 : 范围从 0 到 255
uint16 : 范围从 0 到 65535
uint32 : 范围从 0 到 4294967295
uint64 : 范围从 0 到 18446744073709551615
int8 : 范围从 -128 到 127
int16 : 范围从 -32768 到 32767
int32 : 范围从 -2147483648 到 2147483647
int64 : 范围从 -9223372036854775808 到 9223372036854775807
参考文档 https://golang.org/ref/spec#Numeric_types
Golang 中的数字字面量
在 Golang 中,二进制数10001,可以写为字面量 0x11, 021, 16, 之所以如此, 是因为这些字面量在不同的场景下使用了不同的基数(或者说不同的进制)。
例如,在golang的标准库image/color 中,可以使用16进制的字面量来自定义颜色,如果想使用 颜色 #45bdff, 那么,应表示为:
1 | color.RGBA{0x45, 0xbd, 0xff, 0xff} |
Golang 中的位操作符
& bitwise AND
| bitwise OR
^ bitwise XOR
&^ AND NOT , a&^b 的含义是 AND(a, NOT(b))
<< left shift
>> right shift
示例
00000011 & 00000101 = 00000001
00000011 | 00000101 = 00000111
00000011 ^ 00000101 = 00000110
^00000101 = 11111010
00000011 &^ 00000101 = 00000010
00000101<<2 = 00010100
00000101>>2 = 00000001
上面最后两个位移符号比较常用:
n << x 意味着 "n 乘以 2, 乘 x 次后的整数"
n >> z 意味着 "n 除以 2, 除 z 次后的整数"
例如:
1 << 3 是 "1 乘以 2, 乘3次整数后的整数",结果是 8.
16 >> 2 is "32 除以2 , 除2次后的整数",结果是 4.
用C语言表示为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <stdio.h> int main(void) { int t = 1 ; int i = 3 ; //1 << 3 = 8 printf("%d << %d = %d \n", t, i, t << i); t = 16; i = 2; //16 >> 2 = 4 printf("%d >> %d = %d \n", t, i, t >> i); return 0; } |
问题来了
把给定的一个uint32类型的数字19970701,按照前15bits,中间2bits,最后15bits的规则, 转换为三个uint16类型的数字,并以中横线为间隔符,把这个三个uint16类型的数字连接为字符串输出。输出的字符串为"152-1-14989"。
uint32类型的数字4628440,输出的字符串是"35-1-8152"。
那么,如果给定的uint32数字为20080808,输出的字符串是?
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | package main import ( "fmt" ) func main() { //n := uint32(19970701) //n := uint32(4628440) n := uint32(20080808) fmt.Printf("给定整数%d,的二进制表示: \n%032b\n", n, n) a, b, c := decodeN(n) fmt.Printf("%d-%d-%d\n", a, b, c) } func decodeN(n uint32) (uint16, uint16, uint16) { const mask2 = ^uint32(0) >> (32 - 2) const mask15 = ^uint32(0) >> (32 - 15) //相当于n除以2,除17次的整数,得到 //0000000000100011 //对应整数35 a := uint16(n >> (32 - 15)) //n除以2,除15次,然后和mask2做与运算 //n除以2,除15次,得到整数141 //mask2为 00000000000000000000000000000011 //141 为 00000000000000000000000010001101 //做&运算 00000000000000000000000000000001 b := uint16(n >> (32 - 15 - 2) & mask2) //4628440为 00000000010001101001111111011000 //mask15为 00000000000000000111111111111111 //做&运算 00000000000000000001111111011000 //整数为8152 c := uint16(n & mask15) return a, b, c } |
正确结果是"153-0-26792"。
正确结果并不重要的,重要的是希望你能从这文章中有所收获。
补充
Golang 中和数字与位相关的标准包
https://golang.org/pkg/math/bits/