学径 LearnPath

编程语言基础

运算

计算机的核心能力正是运算。

讲解模式

通过本节课,你将理解:

#goal

变量的值通过运算来进行改变,比如:「加减乘除」、「比较是否相等」等等,这些常用的运算指令,在Python中使用与数学符号类似的 运算符来表示。

但是在计算机中,这些运算的规则,并不完全与数学世界完全一致。

本节课将我们将了解计算机中的基础算术、除法的精度与除零、整除与余数、幂运算,以及布尔运算。

加减乘除与括号

#explore-arithmetic

最常用的算术运算符是 +、-、*、/。它们的含义与数学课大体一致;优先级也一致:先乘除、后加减。

python
result = 2 + 3 * 4
print(result)         # 14

result = (2 + 3) * 4
print(result)         # 20

括号可以用来改变运算顺序,在进行换算的时候,经常需要用到括号。例如将华氏温度转化为摄氏温度:

C=(F−32)×59C = (F - 32) \times \frac{5}{9}
python
fahrenheit = 68
celsius = (fahrenheit - 32) * 5 / 9
print(celsius)

数学课上写多层括号时,习惯用不同形状区分层次,例如 [(3+2)×4]÷2\bigl[(3+2)\times 4\bigr]\div 2。Python 里没有这种写法——无论套几层,一律使用圆括号 ():

python
# 对应 [(3 + 2) × 4] ÷ 2
result = ((3 + 2) * 4) / 2
print(result)  # 10.0

方括号 []、花括号 {} 在 Python 里另有用途,不能拿来当「更大一号的括号」。

除法与精度

#explore-div-precision

但是在计算机中运算并不完全与数学中的相同,有一些奇怪的特点。

数学里,1/31/3 与 1−2/31 - 2/3 是相等的。在计算机里把它们分别算出来再打印,结果并不一致:

python
a = 1 / 3
b = 1 - 2 / 3
print(a)
print(b)

常见输出类似:

text
0.3333333333333333
0.33333333333333337

再试一个加法例子。数学上 0.1+0.2=0.30.1 + 0.2 = 0.3,但在计算机中:

python
sum_ab = 0.1 + 0.2
print(sum_ab)

常见输出是 0.30000000000000004,并不是干净的 0.3。

原因是因为计算机只能使用有限个二进制位存一个数,因此导致的精度问题;许多十进制小数(以及 1/31/3 这类分数)在二进制下是无限循环,机器只能截断或舍入。每一步运算都可能带着这一点点误差,不同的运算顺序累积出不同的尾巴,于是「本该相同」的结果看起来不一致。

我们应该尽可能的避免使用浮点数(小数)计算,如果无法避免请务必考虑精度问题。

除零异常与 try / except

#explore-zero-div

除法并非在所有的值上都有定义。在实数算术里,不允许除数为0。如果你坚持这么做:

python
result = 1 / 0
print(result)

你的程序将会产生名为 ZeroDivisionError 的异常,程序将在那一行停下,并在控制台告诉你原因。

如果你认为这里出现的异常是可以接受,那么你可以用 try / except 结构来捕获异常,并告诉计算机该如何处理:

python
try:
    result = 1 / 0
    print(result)
except ZeroDivisionError:
    result = 0
    print('除数为0,将result强行设定为0')
    print(result)

使用try / except 结构时,请注意代码的 缩进 !也就是代码的前面多出来的空格 ,根据PEP 8的要求,每次缩进应该是4个空格。

在Python中,我们有时需要使用某种特定的结构,用于表示代码不是简单的从上到下的按顺序执行的情况,这些结构会使用:作为开始,并使用缩进来表示内部结构的层级。

整除 // 与余数 %

#explore-divmod

在Python中还支持 //整除与 %模运算,其中模运算也就是求余数的运算。

python
quotient = 17 // 5
remainder = 17 % 5
print(quotient, remainder)  # 3 2

因为 17=5×3+217 = 5\times 3 + 2。

真实项目里,这类运算很常见:

  • 排座 / 装箱:17 个座位按每排 5 个,能排几排、剩几个。
  • 分页:第 nn 条记录落在第几页——page = (n - 1) // page_size。
  • 时间换算:总秒数变成「几分几秒」——minutes = total // 60,seconds = total % 60。
python
total_seconds = 125
minutes = total_seconds // 60
seconds = total_seconds % 60
print(minutes, seconds)  # 2 5

幂运算 **

#explore-power

** 是幂运算,也称为指数运算或乘方。比如2 ** 3 意为2的3次方。

比如求棱长为2的立方体的体积:

python
cube = 2 ** 3
print(cube)              # 8

与数学中的规则相同,幂运算的指数也可以是负数或小数:

python
reciprocal = 2 ** (-1)
print(reciprocal)        # 0.5,求倒数

root = 9 ** 0.5
print(root)              # 3.0,平方根

cube_root = 8 ** (1 / 3)
print(cube_root)         # 约 2.0,立方根

对负数的幂运算,结果可能离开实数域,产生含有虚部的复数结果。Python 运行这样的运算,并给出复数结果:

python
imaginary = (-1) ** 0.5
print(imaginary)
# (6.123233995736766e-17+1j)  — 因为精度问题,实部并没有显示为0,而是一个近似于0的很小的数

比较与逻辑运算

#explore-bool

比较运算符提出真假问题,结果是布尔值 True 或 False:

符号含义
< >小于、大于
<= >=小于等于、大于等于
==是否相等
!=是否不等

先看大于、小于。比较的结果可以直接输出,也同样可以存进变量:

python
score = 85
print(score > 60)  # True
result = score <= 60
print(result)   # False

请注意「是否相等」的是==,单个 = 是赋值!

python
threshold = 0              
is_zero = threshold == 0   # 请注意这行里的=和==意思的区别
print(is_zero)

逻辑运算符把多个真假组合成更复杂的判断,and 与运算,要求要两边都真;or 或运算,有一边真即可;not非运算,翻转真假。:

python
temp = 22
in_range = temp > 0 and temp < 30   # 两边都真才真
print(in_range)

extreme = temp < 0 or temp > 35     # 有一边真就真
print(extreme)

nonzero = not (temp == 0)           # 取反
print(nonzero)

本节练习:分装试剂

#practice

在 在线 IDE 里把 250 克试剂按每瓶 60 克分装:用 // 与 % 分别求出满瓶数和剩余克数并打印,再用 == 判断剩余是否为 0。满瓶应当是 4,剩余应当是 10。

本节要点

#review
  • + - * / 先乘除后加减;括号改变顺序。多层括号在 Python 里一律用 (),不用 [] / {}。
  • 浮点有有限精度:1/3 与 1 - 2/3、0.1 + 0.2 都可能与数学预期不完全一致。尽量少用浮点;无法避免时必须考虑精度。
  • 除数为零会抛出 ZeroDivisionError。try / except 可捕获异常并决定如何处理;结构用 : 开头,内部要缩进(PEP 8:每次 4 个空格)。
  • // 整除、% 取余,适合排座、分页、时间换算等「整份与剩余」问题。
  • ** 是幂运算;指数可为负或小数;对负数开方等运算可能得到复数。
  • < > <= >= == != 得到布尔值;= 是赋值,== 才是判断相等。and / or / not 组合真假。

单选题

括号与运算顺序

result = 2 + 3 * 4 与 result = (2 + 3) * 4 依次得到?

单选题

浮点精度

分别计算 a = 1 / 3 与 b = 1 - 2 / 3 并打印。更准确的说法是?

单选题

除零与 try / except

下面程序没有 try。运行 result = 1 / 0 会发生什么?

单选题

整除与余数

total_seconds = 125 时,minutes = total_seconds // 60 与 seconds = total_seconds % 60 分别是?

单选题

赋值还是比较

要判断变量 score 是否等于 100,应该写成?

未登录时不会保存学习进度