系列文章目录
第一章: 运算符,变量, 数据类型
第二章: 位运算,print函数的使用介绍
第三章 :条件语句与循环语句
第四章:Python 异常处理
第五章:列表,元祖
第二章 位运算,print函数的使用介绍
本系列文章参考自: 天池龙珠计划- python训练营
前言
程序中的所有数在计算机内存中都是以二进制的形式储存的。
位运算就是直接对整数在内存中的二进制位进行操作。比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算。
举个例子:6的二进制是110,11的二进制是1011,那么6 and 11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理)。
print函数在输出结果,程序调试等场景中经常用到,在此对其的常规用法进行介绍。
一、位运算
1. 原码、反码和补码
二进制有三种不同的表示形式:原码、反码和补码,计算机内部使用补码来表示。
原码:就是其二进制表示(注意,有一位符号位)。
00 00 00 11 -> 3
10 00 00 11 -> -3
反码:正数的反码就是原码,负数的反码是符号位不变,其余位取反(对应正数按位取反)。
00 00 00 11 -> 3
11 11 11 00 -> -3
补码:正数的补码就是原码,负数的补码是反码+1。
00 00 00 11 -> 3
11 11 11 01 -> -3
符号位:最高位为符号位,0表示正数,1表示负数。在位运算中符号位也参与运算。
2. 按位运算
- 按位非操作
~
~ 1 = 0
~ 0 = 1
~
把num
的补码中的 0 和 1 全部取反(0 变为 1,1 变为 0)有符号整数的符号位在 ~
运算中同样会取反。
00 00 01 01 -> 5
~
---
11 11 10 10 -> -6
# 按位取反,符号位也取反
11 11 10 11 -> -5
~
---
00 00 01 00 -> 4
- 按位与操作
&
1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0
只有两个对应位都为 1 时才为 1,否则为0
00 00 01 01 -> 5
&
00 00 01 10 -> 6
---
00 00 01 00 -> 4
- 按位或操作
|
1 | 1 = 1
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0
只要两个对应位中有一个 1 时就为 1,两个对应位同时为0时才为0
00 00 01 01 -> 5
|
00 00 01 10 -> 6
---
00 00 01 11 -> 7
- 按位异或操作
^
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0
只有两个对应位不同时才为 1,如果两个对应为同为1或0结果为0
00 00 01 01 -> 5
^
00 00 01 10 -> 6
---
00 00 00 11 -> 3
异或操作的性质:满足交换律和结合律
A: 00 00 11 00
B: 00 00 01 11
A^B: 00 00 10 11
B^A: 00 00 10 11
A^A: 00 00 00 00
A^0: 00 00 11 00
A^B^A: = A^A^B = B = 00 00 01 11
- 按位左移操作
<<
num << i
将num
的二进制表示向左移动i
位所得的值。
在不出现位溢出的情况下,相当于原数据乘以2的i次方
00 00 10 11 -> 11
11 << 3
---
01 01 10 00 -> 88
- 按位右移操作
>>
num >> i
将num
的二进制表示向右移动i
位所得的值。
00 00 10 11 -> 11
11 >> 2
---
00 00 00 10 -> 2
3. 利用位运算实现快速计算
- 通过
<<
,>>
快速计算2的倍数问题。
下面箭头符号(->),表示相当于
n << 1 -> 计算 n*2
n >> 1 -> 计算 n/2,负奇数的运算不可用
n << m -> 计算 n*(2^m),即乘以 2 的 m 次方
n >> m -> 计算 n/(2^m),即除以 2 的 m 次方
1 << n -> 2^n
- 通过
^
快速交换两个整数。
虽然python提供了更简洁的方式交换两个整数的值,即
a, b = b, a
a ^= b
b ^= a
a ^= b
- 通过
a & (-a)
快速获取a
的最后为 1 位置的整数。
00 00 01 01 -> 5
&
11 11 10 11 -> -5
---
00 00 00 01 -> 1
00 00 11 10 -> 14
&
11 11 00 10 -> -14
---
00 00 00 10 -> 2
4. 利用位运算实现整数集合
一个数的二进制表示可以看作是一个集合(0 表示不在集合中,1 表示在集合中)。
比如集合 {1, 3, 4, 8}
,可以表示成 01 00 01 10 10
而对应的位运算也就可以看作是对集合进行的操作。
元素与集合的操作:
a | (1<<i) -> 把 i 插入到集合中
a & ~(1<<i) -> 把 i 从集合中删除
a & (1<<i) -> 判断 i 是否属于该集合(零不属于,非零属于)
集合之间的操作:
a 补 -> ~a
a 交 b -> a & b
a 并 b -> a | b
a 差 b -> a & (~b)
注意:整数在内存中是以补码的形式存在的,输出自然也是按照补码输出。
【例子】C#语言输出负数。
class Program
{
static void Main(string[] args)
{
string s1 = Convert.ToString(-3, 2);
Console.WriteLine(s1);
// 11111111111111111111111111111101
string s2 = Convert.ToString(-3, 16);
Console.WriteLine(s2);
// fffffffd
}
}
【例子】 Python 的bin()
输出。
print(bin(3)) # 0b11
print(bin(-3)) # -0b11
print(bin(-3 & 0xffffffff))
# 0b11111111111111111111111111111101
print(bin(0xfffffffd))
# 0b11111111111111111111111111111101
print(0xfffffffd) # 4294967293
从结果可以看出:
- Python中
bin
一个负数(十进制表示),输出的是它的原码的二进制表示加上个负号,巨坑。 - Python中的整型是补码形式存储的。
- Python中整型是不限制长度的,不会超范围溢出。
所以为了获得负数(十进制表示)的补码,需要手动将其和十六进制数0xffffffff
进行按位与操作,再交给bin()
进行输出,得到的才是负数的补码表示。
二、print函数的使用
函数的使用
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
参数解释:
- 将对象以字符串表示的方式格式化输出到流文件对象file里。其中所有非关键字参数都按
str()
方式进行转换为字符串输出; - 关键字参数
sep
是实现分隔符,比如多个参数输出时想要输出中间的分隔字符; - 关键字参数
end
是输出结束时的字符,默认是换行符\n
; - 关键字参数
file
是定义流输出的文件,可以是标准的系统输出sys.stdout
,也可以重定义为别的文件; - 关键字参数
flush
是立即把内容输出到流文件,不作缓存。
【例子】没有参数时,每次输出后都会换行。
shoplist = ['apple', 'mango', 'carrot', 'banana']
print("This is printed without 'end'and 'sep'.")
for item in shoplist:
print(item)
# This is printed without 'end'and 'sep'.
# apple
# mango
# carrot
# banana
【例子】每次输出结束都用end
设置的参数&
结尾,并没有默认换行。
shoplist = ['apple', 'mango', 'carrot', 'banana']
print("This is printed with 'end='&''.")
for item in shoplist:
print(item, end='&')
print('hello world')
# This is printed with 'end='&''.
# apple&mango&carrot&banana&hello world
【例子】item
值与'another string'
两个值之间用sep
设置的参数&
分割。由于end
参数没有设置,因此默认是输出解释后换行,即end
参数的默认值为\n
。
shoplist = ['apple', 'mango', 'carrot', 'banana']
print("This is printed with 'sep='&''.")
for item in shoplist:
print(item, 'another string', sep='&')
# This is printed with 'sep='&''.
# apple&another string
# mango&another string
# carrot&another string
# banana&another string
字符串格式化输出
字符串格式化使用.format()方法
用法如下:
<模板字符串>.format(<逗号分隔的参数>)
【举例】:
print("{}:计算机{}的CPU占用率为{}%".format("2022-01-02", "C", 10))
# 2022-01-02:计算机C的CPU占用率为10%
# {} - 称为槽,默认将format函数的参数依次填充,也可通过数字控制填充顺序
print("{1}:计算机{0}的CPU占用率为{2}%".format("2022-01-02", "C", 10))
# C:计算机2020-01-02的CPU占用率为10%
槽内部对格式化的配置方式,如下表所示
<:> | <填充> | <对齐> | <宽度> | <,> | <.精度> | <类型> |
---|---|---|---|---|---|---|
引导符号 | 用于填充的单个字符 | < 左对齐> 右对齐^ 居中对齐 | 槽设定的输出宽度 | 数字的千位分隔符 | 浮点数小数精度或字符串最大输出长度 | 整数类型b,c,d,o,x,X 浮点数类型 e,E,f,% |
【例子】定义字符个数,填充字符和对齐方式
# PYTHON居中对齐,填充字符为=,共20个字符
print("{0:=^20}".format("PYTHON"))
# =======PYTHON=======
# BIT右对齐,填充字符为*, 共20个字符
print("{0:*>20}".format("BIT"))
# **************BIT
# 未指定对齐方式,默认左对齐,填充字符为空格
print("{:10}".format("BIT"))
# 'BIT '
【例子】数字的格式化输出
print("{0:,.2f}".format(12345.6789))
# 12,345.68
print("{0:b},{0:c},{0:d},{0:o},{0:x},{0:X}".format(425))
# '110101001,Ʃ,425,651,1a9,1A9'
print("{0:e},{0:E},{0:f},{0:%}".format(3.14))
# '3.140000e+00,3.140000E+00,3.140000,314.000000%'
总结
以上就是今天要讲的内容,本文简单介绍了python编程中涉及到的位运算,介绍了位运算的几种用法,最后介绍了print函数的使用,以及字符串的格式化输出。