01 / 本课学习路线
本课学习路线
阅读与推演约 96 分钟,练习约 55 分钟
02 / 学习目标与先修自测
学完本课你能做什么,以及开始前需要会什么
把矩阵乘法、量化取整与位宽选择结合起来:先核对输入维度,再计算累加上界,最后按行列系数反量化。
| 学完后能做的事 | 正文位置 | 检查方式 |
|---|---|---|
| 算出 128×128×65536 = 2³⁰ 并解释位宽怎么选 | 第 04 节 | 自查第 2 条、练习 5 |
| 解释「整型累加完再一次性反量化」为什么不能换顺序 | 第 04、08 节 | 自查第 3 条 |
| 说出转置输入下 acc 的正确下标写法 | 第 05 节 | 自查第 4 条、代码自测 |
| 说出 sa 对应行、sb 对应列,并举出能检验方向是否互换的样例 | 第 05 节 | 自查第 5 条、练习 2 |
| 输出沿用逢半远离零取整,负值边界方向正确 | 第 06 节 | 自查第 6 条 |
| 通过 AI036 全整型量化矩阵乘法 | 第 05、07 节 | 自查第 1 条 |
先修自测:下面 5 题请先自己写答案,再展开对照。答不出的按括号里的位置补看再回来。本课假定你已完成模块 6 · 第 1 课「矩阵维度与矩阵乘法」和上一课「量化基础:对称与非对称量化」。
| 题号 | 题目 | 补看位置 |
|---|---|---|
| 自测 1 | A 是 m×k、B 是 k×n,C = A×B 的形状是什么?C[i][j] 由 A 的哪一行、B 的哪一列算出? | 矩阵维度与矩阵乘法第 04 节 |
| 自测 2 | sum(x * y for x, y in zip([1, -2, 3], [2, 0, 1])) 是多少? | 常用内置函数 |
| 自测 3 | 2⁷ × 2⁷ × 2¹⁶ 是 2 的几次方?2³¹ − 1 约是多少? | 数字与运算符 |
| 自测 4 | 0.00005 逢半远离零保留 4 位小数是多少?−0.00005 呢? | 量化基础:对称与非对称量化第 04 节 |
| 自测 5 | 输入总共 m×k + n×k + m + n 个记号;data[3 + m*k + j*k : 3 + m*k + (j+1)*k] 取到的是什么? | 输入输出规则、数据范围与精度 |
展开先修自测答案
自测 1:m×n;A 的第 i 行与 B 的第 j 列做点积。本题 B 按转置给,B 的第 j 列就是输入的第 j 行。
自测 2:1×2 + (−2)×0 + 3×1 = 5——样例 1 的 acc[0][0]。
自测 3:2³⁰;2³¹ − 1 ≈ 2.147×10⁹。累加项再多一倍就越过 int32。
自测 4:0.0001 与 −0.0001(远离零)。题库用例 tie-round / neg-tie-round 就是这两个数。
自测 5:Bᵀ 的第 j 行,也就是 B 的第 j 列的 k 个数。
03 / 概念与术语
INT8、累加器、转置输入、行/列缩放系数、反量化
先分清输入矩阵、累加器与行列缩放系数,再核对每个变量的单位和下标。
| 术语 | 含义 | 代码里的位置 |
|---|---|---|
| INT8 矩阵 | 元素范围 −128~127 的整数矩阵;A 是 m×k、B 是 k×n | a_rows、bt_rows |
| 转置输入 Bᵀ | 输入 n 行、每行 k 个数,第 j 行是 B 的第 j 列;算 C[i][j] 时与 A 的第 i 行逐项相乘 | zip(a_rows[i], bt_rows[j]) |
| 累加器 acc | Σ_t A[i][t]·B[t][j],全整数;上界 128×128×k,k ≤ 1.5×10⁵ 时超过 int32 | acc += x * y(Python 整数任意精度) |
| 行 / 列缩放系数 | sa_i 属于 A 的第 i 行,sb_j 属于 B 的第 j 列;C[i][j] = acc·sa_i·sb_j | acc * sa[i] * sb[j] |
| 一次性反量化 | 整数累加完成后才乘缩放系数;中间不出现浮点 | scaled = acc * sa[i] * sb[j] 在内层循环之后 |
| 整数标度 | sa、sb 最多 4 位小数,各乘 10⁴ 存成整数;acc·sa·sb 的单位是 10⁻⁸ | parse_1e4、round_half_away(scaled, 10000) |
| 逢半远离零 | 输出 4 位小数,恰好中点时远离 0 | round_half_away(与上一课相同) |
04 / 一个 2×2 全例
AI036 样例 1 的逐项计算
A=[[1,−2,3],[0,5,−1]],Bᵀ 按行给 [[2,0,1],[−1,4,2]](即 B 的第 0 列是 (2,0,1)、第 1 列是 (−1,4,2)),sa=[0.5,1.0],sb=[0.1,0.25]:
整型累加 → 一次性反量化
acc[0][0] = 1×2 + (−2)×0 + 3×1 = 5 C[0][0] = 5×0.5×0.1 = 0.2500 acc[0][1] = 1×(−1) + (−2)×4 + 3×2 = −3 C[0][1] = −3×0.5×0.25 = −0.3750 acc[1][0] = 0×2 + 5×0 + (−1)×1 = −1 C[1][0] = −1×1.0×0.1 = −0.1000 acc[1][1] = 0×(−1) + 5×4 + (−1)×2 = 18 C[1][1] = 18×1.0×0.25 = 4.5000 把 sa、sb 对调(误写成 acc×sb_i×sa_j)时,C[1][0] = −1×0.25×0.5 = −0.1250——非对称样例可以检验 sa 与 sb 是否对应正确下标
| 量 | 上界 | 结论 |
|---|---|---|
| 单次乘积 |a×b| | 128×128 = 16384 | int16 可以容纳 |
| K=65536 的累加 | 2³⁰ ≈ 1.07×10⁹ | 已贴近 int32 上限 2.15×10⁹ |
| AI036 满规模累加 | 128×128×1.5×10⁵ ≈ 2.5×10⁹ | int32 必溢出 → 64 位 |
根据题目给出的最大绝对值和累加项数量计算上界;若超过 32 位范围,应使用 64 位整数——C++ 用 long long、Java 用 long;Python 的整数是任意精度,不会溢出,但不要提前转 float。
检查项:转置、位宽、缩放方向与输出取整
读入前核对 B 是否按转置给;累加器按 K 上界选位宽;sa 对应行、sb 对应列;输出用逢半远离零取整到 4 位小数。应分别用非对称矩阵、大 K、不同缩放系数和舍入边界输入验证这四项要求,全部正确才能通过全部测试。
补充学习(选学)为什么 B 常按转置提供约 3 分钟按列访问在行主序内存中的非连续性
行主序存储下,按列访问 B 每次要跳 n 个元素,缓存命中率差;把 B 转置后按行给,算 C[i][j] 时 A 的第 i 行和 Bᵀ 的第 j 行都是连续内存。部分推理框架会调整权重布局以提高连续内存访问;本题直接提供 Bᵀ,应按其维度读取——读题时看到就在纸上画一下维度。
05 / 题面示例逐格
转置输入与行/列缩放系数:示例 2 与一组题库用例
AI036「全整型量化矩阵乘法」:第一行 m k n;m 行 A;n 行 Bᵀ;一行 m 个 sa;一行 n 个 sb。C[i][j] = 累加值(acc_ij)× sa_i × sb_j 逢半远离零保留 4 位小数,输出 m 行 n 列。
| 格 | A 的第 i 行 · Bᵀ 的第 j 行 | acc | × sa_i × sb_j | 输出 |
|---|---|---|---|---|
| C[0][0] | (10,0)·(10,0) | 100 | 100 × 0.01 × 0.01 | 0.0100 |
| C[0][1] | (10,0)·(0,10) | 0 | 0 | 0.0000 |
| C[1][0] | (0,10)·(10,0) | 0 | 0 | 0.0000 |
| C[1][1] | (0,10)·(0,10) | 100 | 1.0000 × 0.01 | 0.0100 |
输出 0.0100 0.0000 / 0.0000 0.0100。对称的输入检验不出转置与缩放方向的错误——样例 1 才能。
| 格 | acc | sa_i | sb_j | acc × sa × sb | 输出 |
|---|---|---|---|---|---|
| C[0][0] | 100×100 = 10000 | 1.0 | 0.5 | 5000 | 5000.0000 |
| C[0][1] | 100×1 = 100 | 1.0 | 0.0002 | 0.02 | 0.0200 |
| C[1][0] | 1×100 = 100 | 0.0001 | 0.5 | 0.005 | 0.0050 |
| C[1][1] | 1×1 = 1 | 0.0001 | 0.0002 | 0.00000002 | 0.0000 |
输出 5000.0000 0.0200 / 0.0050 0.0000。把列系数误用成 sa(acc×sa_i×sa_j)会得到 10000.0000 0.0100 / 0.0100 0.0000——四个格里三个不同,这组用例专门检验缩放系数的下标。
06 / 输出取整
整数标度下的逢半远离零
sa、sb 最多 4 位小数,各乘 10⁴ 存成整数后,acc × sa × sb 是「以 10⁻⁸ 为单位」的精确整数;输出要 4 位小数,就是把它除以 10⁴ 再逢半远离零——上一课的 round_half_away(num, den)。
| 输入 | acc × sa × sb | 10⁻⁸ 单位的整数 | ÷ 10⁴ 逢半远离零 | 输出 |
|---|---|---|---|---|
1 1 1 / 1 / 5 / 0.1000 / 0.0001 | 5 × 0.1 × 0.0001 = 0.00005 | 5000 | 0.5 → 1 | 0.0001 |
1 1 1 / -1 / 5 / 0.1000 / 0.0001 | −0.00005 | −5000 | −0.5 → −1 | −0.0001 |
向下取整会把 0.00005 变成 0.0000。直接使用浮点并格式化,在这两组输入上碰巧正确,但不能据此推断其他中点也正确;第 08 节用 5 次乘加展示一次具体分歧。
07 / 从函数到程序
参考实现与完整程序,每一步落在哪几行
先用样例 1 的断言验证 int_matmul(转置取数、整数累加、最后反量化),再补上读入、整数标度与格式化。
| 步骤 | 代码 |
|---|---|
| 读入:m k n、m 行 A、n 行 Bᵀ、sa、sb | a_rows、bt_rows、sa = [parse_1e4(t) …] |
| 整数累加 | for x, y in zip(a_rows[i], bt_rows[j]): acc += x * y |
| 一次性反量化(10⁻⁸ 单位) | scaled = acc * sa[i] * sb[j] |
| 逢半远离零到 4 位小数 | round_half_away(scaled, 10000) |
| 格式化 | fmt_1e4 |
展开参考实现:int_matmul(自带断言;先自己写完再对照)
int_matmul 的参考实现(自带断言)
Python# 以 AI036 样例 1 作为断言:A 是 2×3,Bᵀ 按行给出
A = [[1, -2, 3], [0, 5, -1]]
Bt = [[2, 0, 1], [-1, 4, 2]] # 第 j 行是 B 的第 j 列
sa = [0.5, 1.0]
sb = [0.1, 0.25]
def int_matmul(A, Bt, sa, sb):
m, n = len(A), len(Bt)
C = [[0.0] * n for _ in range(m)]
for i in range(m):
for j in range(n):
acc = 0 # 全整数累加
for x, y in zip(A[i], Bt[j]):
acc += x * y
C[i][j] = acc * sa[i] * sb[j] # 最后一次性反量化
return C
C = int_matmul(A, Bt, sa, sb)
assert [[round(v, 4) for v in r] for r in C] == [[0.25, -0.375], [-0.1, 4.5]]
# 中间量:acc 表是 [[5, -3], [-1, 18]]
assert int_matmul(A, Bt, [1, 1], [1, 1]) == [[5, -3], [-1, 18]]
# 行系数只影响本行、列系数只影响本列:把 sa[0] 翻倍,只有第 0 行翻倍
C2 = int_matmul(A, Bt, [1.0, 1.0], sb)
assert [round(v, 4) for v in C2[0]] == [0.5, -0.75] and [round(v, 4) for v in C2[1]] == [-0.1, 4.5]三条断言:样例 1 的输出;sa、sb 全为 1 时得到 acc 表 [[5, −3], [−1, 18]];把 sa[0] 改成 1.0 只有第 0 行变化——行系数只影响本行。
展开完整参考程序:AI036 全整型量化矩阵乘法
完整程序:AI036(标准输入 → 标准输出)
Pythonimport sys
def round_half_away(num, den):
"""整数精确版:num / den 逢半远离零取整(den > 0)。"""
if num >= 0:
return (2 * num + den) // (2 * den)
return -((-2 * num + den) // (2 * den))
def parse_1e4(token):
"""把最多 4 位小数的十进制文本读成「以 0.0001 为单位」的整数。"""
neg = token.startswith("-")
if neg:
token = token[1:]
whole, _, frac = token.partition(".")
value = int(whole or "0") * 10000 + int((frac + "0000")[:4])
return -value if neg else value
def fmt_1e4(value):
"""把「以 0.0001 为单位」的整数打印成 4 位小数。"""
sign = "-" if value < 0 else ""
value = abs(value)
return f"{sign}{value // 10000}.{value % 10000:04d}"
def main():
data = sys.stdin.read().split()
if not data:
return
m, k, n = int(data[0]), int(data[1]), int(data[2])
pos = 3
a_rows = []
for _ in range(m):
a_rows.append([int(v) for v in data[pos:pos + k]])
pos += k
bt_rows = [] # 第 j 行是 B 的第 j 列
for _ in range(n):
bt_rows.append([int(v) for v in data[pos:pos + k]])
pos += k
sa = [parse_1e4(t) for t in data[pos:pos + m]] # 单位 1e-4
pos += m
sb = [parse_1e4(t) for t in data[pos:pos + n]]
out = []
for i in range(m):
row = []
for j in range(n):
acc = 0 # 整数累加(Python 整数不溢出,语义等于 64 位)
for x, y in zip(a_rows[i], bt_rows[j]):
acc += x * y
scaled = acc * sa[i] * sb[j] # 单位 1e-8
row.append(fmt_1e4(round_half_away(scaled, 10000))) # 除以 1e4 → 单位 1e-4,逢半远离零
out.append(" ".join(row))
print("\n".join(out))
main()累加用 Python 整数,语义等价于 64 位;C++ / Java 请用 long long / long。用题面示例 1 核对:0.2500 -0.3750 / -0.1000 4.5000。
08 / 边界、反例与复杂度
错误做法在题库用例上各输出什么
下面每一行都是一个具体的错误程序,给出输入、错误输出与正确输出;把参考程序改成对应写法就能复现。
| 错误做法 | 输入 | 错误输出 | 正确输出 | 判题结果 |
|---|---|---|---|---|
先执行 bt_rows = list(zip(*bt_rows)),再沿用按行 zip 点积 | 题面示例 1 | 0.2000 -1.0000 / -0.5000 5.0000(zip 截到较短行,漏掉乘积) | 0.2500 -0.3750 / -0.1000 4.5000 | 答案错误(WA) |
| 列系数误用行系数(acc×sa_i×sa_j) | 2 1 2 / 100 / 1 / 100 / 1 / 1.0000 0.0001 / 0.5000 0.0002 | 10000.0000 0.0100 / 0.0100 0.0000 | 5000.0000 0.0200 / 0.0050 0.0000 | 答案错误(WA) |
| 32 位有符号累加(C++ int / Java int) | 1 140000 1 / 127…(140000 个)/ …(题库 int32-overflow) | 2019127296.0000(按 2³² 回绕) | -2275840000.0000 | 答案错误(WA) |
逐项执行 acc += (x * sa) * (y * sb),最后格式化 | 1 5 1 / 1 1 1 1 1 / 1 1 1 1 1 / 0.7000 / 0.0001 | 0.0003(浮点累加约 0.00034999999999999994) | 0.0004(精确值 0.00035,逢半远离零) | 答案错误(WA) |
| 向下取整代替逢半远离零 | 1 1 1 / 1 / 5 / 0.1000 / 0.0001 | 0.0000 | 0.0001 | 答案错误(WA) |
错误实现必须按表中写法复现:第一行若直接访问 bt_rows[t][j],非方阵还可能越界;浮点一行的乘法与累加顺序见下面的独立脚本。32 位回绕可在 Python 中对 2³² 取模后转回有符号区间模拟;Java int 按此回绕,C++ 有符号溢出不保证回绕结果,应避免触发。
独立运行:5 次乘加如何跨过四位小数的舍入中点
Python# 同一输入:整数累加后反量化,与逐项浮点反量化后累加
row = [1, 1, 1, 1, 1]
column = [1, 1, 1, 1, 1]
sa, sb = 0.7, 0.0001
wrong = 0.0
for x, y in zip(row, column):
wrong += (x * sa) * (y * sb)
print(f"{wrong:.4f}") # 0.0003:实际累加值约 0.00034999999999999994
acc = sum(x * y for x, y in zip(row, column))
scaled = acc * 7000 * 1 # sa、sb 各以 1e-4 为单位,乘积以 1e-8 为单位
units = (2 * scaled + 10000) // 20000 # 本例为正数:除以 1e4,逢半远离零
print(f"{units // 10000}.{units % 10000:04d}") # 0.0004
assert f"{wrong:.4f}" == "0.0003" and units == 4第一行应输出 0.0003,第二行应输出 0.0004。精确计算为 acc=5,5×0.7×0.0001=0.00035;脚本只说明所列浮点顺序在这组输入上出错,不声称所有浮点写法都产生同一误差。
| 做法 | 时间 | 本课规模下 |
|---|---|---|
| 三重循环整数累加 | O(m·n·k) | (m+n)×k ≤ 4×10⁵ 时最多约 10⁷ 次乘加(m=n=50、k=4000);在目标语言和评测环境中核对耗时 |
| 先把 Bᵀ 转回 B 再按列取 | O(m·n·k) 但每次跳行访问 | 结果相同,C++ 里缓存命中差;Python 里多一层下标反而慢 |
09 / 渐进练习与参考答案
跟做 → 改一个条件 → 独立实现 → 迁移
每题先在纸上或文件里做完,再展开答案。
练习 1(跟做):按第 04 节的格式,把题库用例 2 2 2 / 127 -128 / -128 127 / 127 127 / -128 -128 / 1.0000 0.5000 / 0.2500 1.0000 的四个 acc 与输出算出来。
展开练习 1 答案
acc[0][0] = 127×127 + (−128)×127 = −127;acc[0][1] = 127×(−128) + (−128)×(−128) = 128;acc[1][0] = −128×127 + 127×127 = −127;acc[1][1] = −128×(−128) + 127×(−128) = 128。C = [[−127×1×0.25, 128×1×1], [−127×0.5×0.25, 128×0.5×1]] = -31.7500 128.0000 / -15.8750 64.0000(题库用例 extreme-int8)。
练习 2(改一个条件):样例 1 把 sa 改成 [1.0, 0.5]、sb 不变,输出是什么?哪些格变了?
展开练习 2 答案
acc 表不变 [[5, −3], [−1, 18]]。第 0 行乘 1.0:0.5000、−0.7500;第 1 行乘 0.5:−0.0500、2.2500。输出 0.5000 -0.7500 / -0.0500 2.2500——两行都变了,因为两个 sa 都改了;只改 sa[0] 时只有第 0 行变(第 07 节断言)。
练习 3(改一个条件):k 从 3 增加到 150000、元素全是 −128 与 127,acc 的绝对值最大是多少?它超过 int32 了吗?
展开练习 3 答案
每项乘积绝对值最大 128×128 = 16384,150000 项最大 2.4576×10⁹,超过 2³¹ − 1 ≈ 2.147×10⁹——必须 64 位。题库 int32-overflow 用例 k=140000 已经越界(正确 −2275840000)。
练习 4(独立实现):完成「必做任务 1」的 int_matmul,再加一条断言:sa、sb 全为 1 时返回 acc 表 [[5, −3], [−1, 18]]。
展开练习 4 答案
int_matmul 的参考实现(自带断言)
Python# 以 AI036 样例 1 作为断言:A 是 2×3,Bᵀ 按行给出
A = [[1, -2, 3], [0, 5, -1]]
Bt = [[2, 0, 1], [-1, 4, 2]] # 第 j 行是 B 的第 j 列
sa = [0.5, 1.0]
sb = [0.1, 0.25]
def int_matmul(A, Bt, sa, sb):
m, n = len(A), len(Bt)
C = [[0.0] * n for _ in range(m)]
for i in range(m):
for j in range(n):
acc = 0 # 全整数累加
for x, y in zip(A[i], Bt[j]):
acc += x * y
C[i][j] = acc * sa[i] * sb[j] # 最后一次性反量化
return C
C = int_matmul(A, Bt, sa, sb)
assert [[round(v, 4) for v in r] for r in C] == [[0.25, -0.375], [-0.1, 4.5]]
# 中间量:acc 表是 [[5, -3], [-1, 18]]
assert int_matmul(A, Bt, [1, 1], [1, 1]) == [[5, -3], [-1, 18]]
# 行系数只影响本行、列系数只影响本列:把 sa[0] 翻倍,只有第 0 行翻倍
C2 = int_matmul(A, Bt, [1.0, 1.0], sb)
assert [round(v, 4) for v in C2[0]] == [0.5, -0.75] and [round(v, 4) for v in C2[1]] == [-0.1, 4.5]见第 07 节展开区(同一份代码,第二条断言就是本题)。
练习 5(迁移):如果题目改成 A、B 是 INT4(范围 −8~7),k 最大 10⁶,累加器用 int32 够吗?
展开练习 5 答案
每项最大 8×8 = 64,10⁶ 项最大 6.4×10⁷,远小于 2.147×10⁹——int32 够。位宽结论来自「单项上界 × 项数」,不是来自输入位宽本身。
10 / 读题要求与复习自评
AI036 的要求对照,以及完成本课之后怎么复习
提交前把下表过一遍;题目页的题面与样例是最终依据。
| 项目 | 要求 | 对应代码 |
|---|---|---|
| 输入布局 | m k n;m 行 A(每行 k 个);n 行 Bᵀ(每行 k 个,第 j 行是 B 的第 j 列);一行 m 个 sa;一行 n 个 sb | a_rows / bt_rows / sa / sb |
| 累加 | 64 位有符号整数(k ≤ 1.5×10⁵,32 位会溢出) | Python 整数;C++ long long、Java long |
| 反量化 | C[i][j] = acc × sa_i × sb_j,整数累加完成后一次性乘 | scaled = acc * sa[i] * sb[j] |
| 输出 | m 行 n 列,4 位小数,逢半远离零 | round_half_away(scaled, 10000)、fmt_1e4 |
| 规模 | m、n ≤ 50,k ≤ 150000,(m+n)×k ≤ 4×10⁵ | 结合输入总量估算 m·n·k,避免内层重复解析与转换 |
参考程序:需要对照解法时,展开第 07 节的完整程序。复习与自评:「学习完成检查」六条是自评,勾选不改变题目的通过(AC)状态。本课记为完成的条件:必做题 AI036 通过,并勾选全部六条学习完成检查;复习题不计入完成状态。复习时用三个问题自测:① 不看正文,写出 acc 的下标写法(Bᵀ 的第 j 行);② 不看表格,重算样例 1 的四个 acc;③ 说出 128×128×65536 是 2 的几次方、为什么 K=1.5×10⁵ 必须 64 位。答不出哪一条,就回到对应的节重读,再做第 09 节对应的练习。
11 / 练习
按顺序完成本课的任务
必做题已通过 0/1 道
整数矩阵乘法函数(int_matmul):以样例 1 作断言
必做任务 1自主练习练习重点:整型累加、Bᵀ 行序取数、sa_i×sb_j 反量化;预计用时:15 分钟
完成标准:断言结果正确,并能展开计算 acc[0][1]=−3
需要时查看提示
acc[i][j] = sum(A[i][t] * Bt[j][t] for t in range(k))——注意第二个下标是 Bt[j][t] 不是 Bt[t][j],这正是转置输入的意义。参考实现在第 07 节。
自测代码(复制到你的代码文件中运行,检查输出是否一致)
# 以 AI036 样例 1 作为断言:A 是 2×3,Bᵀ 按行给出
A = [[1, -2, 3], [0, 5, -1]]
Bt = [[2, 0, 1], [-1, 4, 2]] # 第 j 行是 B 的第 j 列
sa = [0.5, 1.0]
sb = [0.1, 0.25]
def int_matmul(A, Bt, sa, sb):
# 待完成:全整数累加 acc,最后 C[i][j] = acc * sa[i] * sb[j]
...
C = int_matmul(A, Bt, sa, sb)
assert [[round(v, 4) for v in r] for r in C] == [[0.25, -0.375], [-0.1, 4.5]]AI036 · 全整型量化矩阵乘法
必做任务 2练习重点:64 位累加、转置读入、行/列缩放系数、逢半远离零定标输出;预计用时:40 分钟
完成标准:能说出四项规则各自用什么输入验证
需要时查看提示
C++/Java 累加器必须 64 位(K 到 1.5×10⁵);Python 不要提前转 float;输出保留 4 位、逢半远离零,−0.00005 舍向 −0.0001;整型累加完再一次性乘 sa_i×sb_j。第 05 节有两组逐格表。
提交结果
提交结果说明与处理方法
- WA
答案错误
四查:B 是否被多转了一次、sa/sb 方向、是否先乘缩放系数再累加(应最后一次性乘)、输出舍入方向。第 08 节的表给出了每种错误在题库用例上的输出
- PE
格式错误
每行 n 个数、保留 4 位小数、单空格分隔;行尾无多余空格
- RE
运行错误
核对输入总数是否为 m×k + n×k + m + n;字段数量错误会使后续解析位置偏移
- TLE
超时
根据数据范围核对 O(m·n·k) 的运算量((m+n)×k ≤ 4×10⁵ 时最多约 10⁷ 次乘加),并在目标语言和评测环境中验证;必要时减少 Python 循环层级和重复索引
- AC
通过
构造包含 −128 边界值且 K 取上限的输入,验证累加器位宽
12 / 学习完成检查
本课学习完成检查
完成本课需要:必做题全部通过,并勾选本课的全部学习完成检查;进阶练习、基础加练与复习题单独统计,不影响完成状态。登录后,勾选记录会保存到账号,并更新课程总览的完成状态。