第 1 章 从算术到函数
学习目标
- 理解变量与代数式,会代入求值
- 理解函数的定义:一台「输入 → 输出」的机器
- 会画一次函数、二次函数的图像
- 理解一次函数的斜率与截距
- 理解平均变化率(割线的斜率)
- 会用 NumPy 批量计算函数值,用 matplotlib 画函数图像
1.1 变量与代数式
小学里学的算术,数字都是具体的:,。可是生活里有很多数是不确定的:一本书多少钱?一块橡皮多少钱?总价会随单价变化。为了表示「还不确定的数」,数学里用字母代表它,这个字母叫变量。
变量:一个可以取不同数值的字母或符号。
比如一支笔 元,买 3 支要 元。这里的 是变量, 叫代数式:用运算符号把数、字母连接起来的式子。把 的具体值代进去计算,叫代入求值:
注意代数式里的书写约定: 表示「3 乘以 x」,乘号省略不写; 表示「x 乘以 x」。
再看一个例子。正方形边长记作 ,那么:
- 周长
- 面积
当 时,代入得 、。同一个式子,换一个 就得到另一个结果,这就是「代数」和「算术」的区别:算术算的是具体的数,代数研究的是「式子怎么随变量变化」。
1.2 函数:一台「输入 → 输出」的机器
把「代数式」升级一下:先给一个数 ,按一套固定的运算,得到一个数 。这套固定的规则,就叫函数。
函数(function):对于每一个输入 ,按照确定的规则,恰好得到一个输出 ,记作
读作「 等于 在 处的值」。 是规则的名字,括号里的 是输入。
函数有三个关键词,缺一不可:
- 每一个输入都有输出:不能「有的输入算不出结果」;
- 恰好一个输出:同一个输入不能给出两个不同的输出;
- 规则确定:同样的输入,永远得到同样的输出。
生活中的例子:
- 温度换算:,把摄氏度 变成华氏度。 时,,水在 1 个标准大气压下沸腾。
- 正方形面积:。 是边长,面积由边长唯一决定。
- 出租车计价:起步价 13 元,之后每公里 2.3 元,,其中 是行驶公里数。
函数还有三个「零件」,合称三要素:
- 定义域:允许的输入 的全体。比如面积 ,边长不能是负数,定义域是 。本书默认:定义域是「让式子有意义的所有实数」。
- 对应法则:把输入变成输出的规则,即式子本身。
- 值域:所有可能的输出 的全体。
为什么函数的输出必须唯一? 因为现实里的「因果关系」就是这样:同一个原因不会产生两个不同结果。今天 37°C 不会既是 98.6°F 又是 100°F。数学把这种「确定性」提炼成函数的概念,后面学导数、积分时,处处都要用到「函数值唯一」。
1.3 函数的图像:把「对应关系」画出来
一个函数有一大堆输入输出对 :输入 得到 ,输入 得到 ……把它们全部画在坐标平面上,就得到函数的图像。
先回顾坐标平面(从小学基础出发,这里补全细节):
- 两条数轴垂直交叉:横的叫 轴,竖的叫 轴;
- 交点叫原点 ;
- 点 :先沿 轴走横坐标这么多格,再沿 轴走纵坐标这么多格。
描点法画函数图像,只有三步:
- 取几个 (要覆盖不同位置,包括负数);
- 逐个算出 ;
- 把点 标出来,用平滑的线连起来。
以 为例,列出函数值表:
这些点关于 轴对称,连起来是向上开口的抛物线。为什么 和 的函数值相等?因为 ,两个负数相乘得正数。这条曲线后面会反复出现。
用 NumPy 一次算出整张表,再用 matplotlib 画图:
import numpy as np
x = np.array([-2, -1, 0, 1, 2])
f = x ** 2
print("x =", x)
print("x² =", f)x = [-2 -1 0 1 2]
x² = [4 1 0 1 4]NumPy 里的 x ** 2 对数组里的每一个数分别做平方,这正是函数的批量运算:一个数组进来,一个数组出去,每个输入对应唯一输出。
import matplotlib.pyplot as plt
from matplotlib import font_manager
for f in font_manager.findSystemFonts():
if any(k in f for k in ("NotoSansCJK", "NotoSansSC", "wqy", "SimHei", "msyh", "PingFang")):
font_manager.fontManager.addfont(f)
plt.rcParams["font.sans-serif"] = ["Noto Sans CJK SC", "WenQuanYi Zen Hei", "SimHei", "Microsoft YaHei", "PingFang SC"]
plt.rcParams["axes.unicode_minus"] = False
import numpy as np
x = np.linspace(-2.5, 2.5, 300)
f = x ** 2
fig, ax = plt.subplots(figsize=(6, 5))
ax.plot(x, f, color="tab:blue", label="f(x) = x²")
ax.axhline(0, color="black", linewidth=0.8)
ax.axvline(0, color="black", linewidth=0.8)
ax.scatter([-2, -1, 0, 1, 2], [4, 1, 0, 1, 4], color="tab:red", zorder=3)
ax.set_xlim(-3, 3)
ax.set_ylim(-1, 6)
ax.set_aspect("equal")
ax.grid(True, linestyle=":", alpha=0.5)
ax.legend()
ax.set_title("函数图像:描点 f(x) = x²")
fig.savefig("book/public/figs/fig01-quadratic.png", dpi=120, bbox_inches="tight")
plt.close(fig)
1.4 一次函数与斜率
一次函数:形如
的函数(、 是常数,)。它的图像是一条直线,所以也叫线性函数。
名字里的「一次」,指的是 的次数是 1()。 叫斜率, 叫纵截距。
纵截距:图像与 轴交点的纵坐标。因为当 时,,所以交点就是 。
斜率衡量直线的倾斜程度,定义是「纵坐标的变化量 ÷ 横坐标的变化量」:
符号 (读作 delta)表示「变化量」: 是纵坐标的变化, 是横坐标的变化。
推导:直线上任取两点 、,既然它们都在直线 上,就都有:
用第二个式子减第一个式子:
这里用了三个规则: 消去截距;分配律 反过来用。两边除以 (要求 ,否则横坐标没变化、谈不上「倾斜」),就得到
斜率的几何含义:
- :直线向右上方倾斜,越往右越高;
- :直线向右下方倾斜,越往右越低;
- 越大,直线越陡。
看 :斜率 ,截距 。取两点 和 验证:
与 一致。意思是:横坐标每增加 1, 增加 2。
x1, y1 = 1, 3
x2, y2 = 3, 7
k = (y2 - y1) / (x2 - x1)
print("斜率 k =", k)斜率 k = 2.0画出来看斜率与截距:
import matplotlib.pyplot as plt
from matplotlib import font_manager
for f in font_manager.findSystemFonts():
if any(k in f for k in ("NotoSansCJK", "NotoSansSC", "wqy", "SimHei", "msyh", "PingFang")):
font_manager.fontManager.addfont(f)
plt.rcParams["font.sans-serif"] = ["Noto Sans CJK SC", "WenQuanYi Zen Hei", "SimHei", "Microsoft YaHei", "PingFang SC"]
plt.rcParams["axes.unicode_minus"] = False
import numpy as np
x = np.linspace(-1.5, 3.5, 300)
y = 2 * x + 1
fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(x, y, color="tab:blue", label="y = 2x + 1")
ax.axhline(0, color="black", linewidth=0.8)
ax.axvline(0, color="black", linewidth=0.8)
# 两点与 Δx、Δy
p1, p2 = (1, 3), (3, 7)
ax.scatter([p1[0], p2[0]], [p1[1], p2[1]], color="tab:red", zorder=3)
ax.annotate("(1, 3)", p1, textcoords="offset points", xytext=(-18, -16), color="tab:red")
ax.annotate("(3, 7)", p2, textcoords="offset points", xytext=(8, -16), color="tab:red")
ax.annotate("", xy=p2, xytext=(p1[0], p1[1]),
arrowprops=dict(arrowstyle="->", color="tab:green", lw=1.5))
ax.annotate("", xy=(p2[0], p1[1]), xytext=(p1[0], p1[1]),
arrowprops=dict(arrowstyle="->", color="tab:orange", lw=1.5))
ax.text(2.05, 3.4, "Δy = 4", color="tab:green", fontsize=12)
ax.text(2.05, 2.4, "Δx = 2", color="tab:orange", fontsize=12)
ax.text(2.45, 5.4, "斜率 = Δy/Δx = 2", color="tab:blue", fontsize=12)
ax.set_xlim(-2, 4)
ax.set_ylim(-2, 9)
ax.set_aspect("equal")
ax.grid(True, linestyle=":", alpha=0.5)
ax.legend(loc="upper left")
ax.set_title("一次函数 y = 2x + 1:斜率与截距")
fig.savefig("book/public/figs/fig01-line.png", dpi=120, bbox_inches="tight")
plt.close(fig)
1.5 平均变化率:任何函数的「斜率」
不是所有函数都是直线。二次函数 (一辆车 小时开出的路程)的图像是弯曲的。弯曲的线没有「唯一的斜率」,但我们可以问:从 到 ,它平均每单位时间变化了多少?
平均变化率:函数 在区间 上的平均变化率定义为
它和一次函数斜率的公式一模一样,只是分子里的 、 换成了 、。
几何意义:连接图像上两点 、 的直线叫割线(secant),平均变化率就是这条割线的斜率。
算一下那辆车从 1 小时到 3 小时的平均速度:
「平均速度 80 km/h」不代表车一直开 80:它可能有时快有时慢,但「总路程 ÷ 总时间」这个整体平均值是 80。这正是下一章「瞬时速度」的出发点:把区间越缩越小,平均变化率会趋向一个极限。
def s(t):
return 60 * t + 5 * t ** 2
v_avg = (s(3) - s(1)) / (3 - 1)
print("1 到 3 小时的平均速度 =", v_avg, "km/h")1 到 3 小时的平均速度 = 80.0 km/h画出路程曲线和割线,直观看到「平均变化率 = 割线斜率」:
import matplotlib.pyplot as plt
from matplotlib import font_manager
for f in font_manager.findSystemFonts():
if any(k in f for k in ("NotoSansCJK", "NotoSansSC", "wqy", "SimHei", "msyh", "PingFang")):
font_manager.fontManager.addfont(f)
plt.rcParams["font.sans-serif"] = ["Noto Sans CJK SC", "WenQuanYi Zen Hei", "SimHei", "Microsoft YaHei", "PingFang SC"]
plt.rcParams["axes.unicode_minus"] = False
import numpy as np
def s(t):
return 60 * t + 5 * t ** 2
t = np.linspace(0, 4, 300)
fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(t, s(t), color="tab:blue", label="s(t) = 60t + 5t²")
t1, t2 = 1, 3
ax.plot([t1, t2], [s(t1), s(t2)], color="tab:red", linestyle="--", label="割线")
ax.scatter([t1, t2], [s(t1), s(t2)], color="tab:red", zorder=3)
ax.annotate("(1, 65)", (t1, s(t1)), textcoords="offset points", xytext=(10, -18), color="tab:red")
ax.annotate("(3, 225)", (t2, s(t2)), textcoords="offset points", xytext=(10, 6), color="tab:red")
ax.annotate("", xy=(t2, s(t1)), xytext=(t1, s(t1)),
arrowprops=dict(arrowstyle="->", color="tab:orange", lw=1.5))
ax.annotate("", xy=(t2, s(t2)), xytext=(t2, s(t1)),
arrowprops=dict(arrowstyle="->", color="tab:green", lw=1.5))
ax.text(1.35, 70, "Δt = 2", color="tab:orange", fontsize=12)
ax.text(2.45, 128, "Δs = 160", color="tab:green", fontsize=12)
ax.text(2.1, 105, "平均变化率 = 80", color="tab:red", fontsize=12)
ax.set_xlim(0, 4.4)
ax.set_ylim(0, 270)
ax.set_xlabel("时间 t(小时)")
ax.set_ylabel("路程 s(千米)")
ax.grid(True, linestyle=":", alpha=0.5)
ax.legend()
ax.set_title("平均变化率:割线的斜率")
fig.savefig("book/public/figs/fig01-avg_change.png", dpi=120, bbox_inches="tight")
plt.close(fig)
1.6 动手实践:温度换算表
用函数 生成摄氏温度到华氏温度的换算表:
import numpy as np
def f(celsius):
return 1.8 * celsius + 32
celsius = np.array([0, 20, 37, 100])
fahrenheit = f(celsius)
print("摄氏:", celsius)
print("华氏:", fahrenheit)摄氏: [ 0 20 37 100]
华氏: [ 32. 68. 98.6 212. ]这张表验证了函数的两件事:每个输入恰好一个输出;同样的规则反复可用。 对应 (人体体温), 对应 (水的沸点)。
常见错误
| 错误写法/理解 | 原因 |
|---|---|
| 把 读成「3 和 x 相加」 | 代数式里数字与字母并排表示相乘, |
| 认为「输入一个数,函数可以给出两个输出」 | 函数的定义要求输出唯一;否则就不是函数 |
| 斜率算成 | 斜率是「纵坐标变化 ÷ 横坐标变化」,分子分母不能颠倒 |
| 把平均变化率 写成 | 同样是「纵比横」;颠倒后单位都反了 |
| 取 代入斜率公式 | 分母为 0,没有意义;斜率要求横坐标确实发生变化 |
| matplotlib 图中中文显示为方块 | 缺中文字体:按上文字体设置代码加载系统字体 |
章末练习
基础
- 边长 的正方形,周长与面积各是多少?写出代数式再代入。
- 已知 ,求 、、。
- 求过 与 的直线的斜率,并写出这条直线的一次函数式。
提高
- 一次函数 过 与 :先用斜率公式求 ,再代入任一点求 ,写出完整的函数式。
- 自由落体路程 ( 秒,单位米)。求 2 秒到 4 秒的平均速度,写出每一步推导。
挑战
- 证明:任何一次函数 的任意两点算出的 都等于同一个常数 。
- 用 NumPy 生成 在 处的函数值表,并画出图像,观察它的最高点出现在哪个 附近。
章末自测
每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。
- 一支笔 元,买 5 支,总价是?
- A.
- B.
- C.
- D.
- 中, 等于?
- A.
- B.
- C.
- D.
- 函数的定义要求:同一个输入必须得到?
- A. 至少一个输出
- B. 恰好一个输出
- C. 两个输出
- D. 输出比输入大
- 一次函数 的图像?
- A. 向右上方倾斜
- B. 向右下方倾斜
- C. 水平
- D. 竖直
- 直线 与 轴的交点是?
- A.
- B.
- C.
- D.
- 过 与 的直线,斜率是?
- A.
- B.
- C.
- D.
- 函数 在区间 上的平均变化率是 。若 、,平均变化率是?
- A.
- B.
- C.
- D.
- 平均变化率的几何意义是?
- A. 切线的斜率
- B. 割线的斜率
- C. 曲线的高度
- D. 曲线与 x 轴的交点
- NumPy 中,对数组
x的每个元素求平方的写法是?- A.
x * x - B.
x ** 2 - C. 两者都可以
- D. 都不行
- A.
- 在 时的函数值 是?
- A.
- B.
- C.
- D.
